[libflac] New Library Added. Unnecessary files and folders are cleaned up.
authorprince <prince.dubey@samsung.com>
Thu, 13 Oct 2011 06:23:14 +0000 (15:23 +0900)
committerprince <prince.dubey@samsung.com>
Thu, 13 Oct 2011 07:45:53 +0000 (16:45 +0900)
Change-Id: I86c1714f4a0406b232f5eb9d4736dedc19f2d0c1

556 files changed:
AUTHORS [new file with mode: 0644]
COPYING.FDL [new file with mode: 0644]
COPYING.GPL [new file with mode: 0644]
COPYING.LGPL [new file with mode: 0644]
COPYING.Xiph [new file with mode: 0644]
FLAC.dsw [new file with mode: 0644]
FLAC.sln [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.lite [new file with mode: 0644]
README [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
all.dsp [new file with mode: 0644]
all_dynamic.dsp [new file with mode: 0644]
all_static.dsp [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
build/Makefile.am [new file with mode: 0644]
build/config.mk [new file with mode: 0644]
build/exe.mk [new file with mode: 0644]
build/lib.mk [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.h.in [new file with mode: 0644]
config.rpath [new file with mode: 0755]
config.sub [new file with mode: 0755]
configure.ac [new file with mode: 0644]
debian/changelog [new file with mode: 0755]
debian/compat [new file with mode: 0755]
debian/control [new file with mode: 0755]
debian/copyright [new file with mode: 0755]
debian/libflac-dev.install [new file with mode: 0644]
debian/libflac.install [new file with mode: 0755]
debian/rules [new file with mode: 0755]
depcomp [new file with mode: 0755]
examples/Makefile.am [new file with mode: 0644]
examples/Makefile.lite [new file with mode: 0644]
examples/README [new file with mode: 0644]
examples/c/Makefile.am [new file with mode: 0644]
examples/c/decode/Makefile.am [new file with mode: 0644]
examples/c/decode/file/Makefile.am [new file with mode: 0644]
examples/c/decode/file/Makefile.lite [new file with mode: 0644]
examples/c/decode/file/example_c_decode_file.dsp [new file with mode: 0644]
examples/c/decode/file/example_c_decode_file.vcproj [new file with mode: 0644]
examples/c/decode/file/main.c [new file with mode: 0644]
examples/c/encode/Makefile.am [new file with mode: 0644]
examples/c/encode/file/Makefile.am [new file with mode: 0644]
examples/c/encode/file/Makefile.lite [new file with mode: 0644]
examples/c/encode/file/example_c_encode_file.dsp [new file with mode: 0644]
examples/c/encode/file/example_c_encode_file.vcproj [new file with mode: 0644]
examples/c/encode/file/main.c [new file with mode: 0644]
examples/cpp/Makefile.am [new file with mode: 0644]
examples/cpp/decode/Makefile.am [new file with mode: 0644]
examples/cpp/decode/file/Makefile.am [new file with mode: 0644]
examples/cpp/decode/file/Makefile.lite [new file with mode: 0644]
examples/cpp/decode/file/example_cpp_decode_file.dsp [new file with mode: 0644]
examples/cpp/decode/file/example_cpp_decode_file.vcproj [new file with mode: 0644]
examples/cpp/decode/file/main.cpp [new file with mode: 0644]
examples/cpp/encode/Makefile.am [new file with mode: 0644]
examples/cpp/encode/file/Makefile.am [new file with mode: 0644]
examples/cpp/encode/file/Makefile.lite [new file with mode: 0644]
examples/cpp/encode/file/example_cpp_encode_file.dsp [new file with mode: 0644]
examples/cpp/encode/file/example_cpp_encode_file.vcproj [new file with mode: 0644]
examples/cpp/encode/file/main.cpp [new file with mode: 0644]
examples/examples.dsp [new file with mode: 0644]
include/FLAC++/Makefile.am [new file with mode: 0644]
include/FLAC++/all.h [new file with mode: 0644]
include/FLAC++/decoder.h [new file with mode: 0644]
include/FLAC++/encoder.h [new file with mode: 0644]
include/FLAC++/export.h [new file with mode: 0644]
include/FLAC++/metadata.h [new file with mode: 0644]
include/FLAC/Makefile.am [new file with mode: 0644]
include/FLAC/all.h [new file with mode: 0644]
include/FLAC/assert.h [new file with mode: 0644]
include/FLAC/callback.h [new file with mode: 0644]
include/FLAC/export.h [new file with mode: 0644]
include/FLAC/format.h [new file with mode: 0644]
include/FLAC/metadata.h [new file with mode: 0644]
include/FLAC/ordinals.h [new file with mode: 0644]
include/FLAC/stream_decoder.h [new file with mode: 0644]
include/FLAC/stream_encoder.h [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/share/Makefile.am [new file with mode: 0644]
include/share/alloc.h [new file with mode: 0644]
include/share/getopt.h [new file with mode: 0644]
include/share/grabbag.h [new file with mode: 0644]
include/share/grabbag/Makefile.am [new file with mode: 0644]
include/share/grabbag/cuesheet.h [new file with mode: 0644]
include/share/grabbag/file.h [new file with mode: 0644]
include/share/grabbag/picture.h [new file with mode: 0644]
include/share/grabbag/replaygain.h [new file with mode: 0644]
include/share/grabbag/seektable.h [new file with mode: 0644]
include/share/replaygain_analysis.h [new file with mode: 0644]
include/share/replaygain_synthesis.h [new file with mode: 0644]
include/share/utf8.h [new file with mode: 0644]
include/test_libs_common/Makefile.am [new file with mode: 0644]
include/test_libs_common/file_utils_flac.h [new file with mode: 0644]
include/test_libs_common/metadata_utils.h [new file with mode: 0644]
install-sh [new file with mode: 0755]
ltmain.sh [new file with mode: 0644]
m4/Makefile.am [new file with mode: 0644]
m4/ogg.m4 [new file with mode: 0644]
m4/xmms.m4 [new file with mode: 0644]
man/Makefile.am [new file with mode: 0644]
man/flac.1 [new file with mode: 0644]
man/flac.sgml [new file with mode: 0644]
man/metaflac.1 [new file with mode: 0644]
man/metaflac.sgml [new file with mode: 0644]
missing [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
src/Makefile.am [new file with mode: 0644]
src/Makefile.lite [new file with mode: 0644]
src/flac/Makefile.am [new file with mode: 0644]
src/flac/Makefile.lite [new file with mode: 0644]
src/flac/Makefile.lite.iffscan [new file with mode: 0644]
src/flac/analyze.c [new file with mode: 0644]
src/flac/analyze.h [new file with mode: 0644]
src/flac/decode.c [new file with mode: 0644]
src/flac/decode.h [new file with mode: 0644]
src/flac/encode.c [new file with mode: 0644]
src/flac/encode.h [new file with mode: 0644]
src/flac/flac.dsp [new file with mode: 0644]
src/flac/flac.vcproj [new file with mode: 0644]
src/flac/foreign_metadata.c [new file with mode: 0644]
src/flac/foreign_metadata.h [new file with mode: 0644]
src/flac/iffscan.c [new file with mode: 0644]
src/flac/iffscan.dsp [new file with mode: 0644]
src/flac/iffscan.vcproj [new file with mode: 0644]
src/flac/local_string_utils.c [new file with mode: 0644]
src/flac/local_string_utils.h [new file with mode: 0644]
src/flac/main.c [new file with mode: 0644]
src/flac/utils.c [new file with mode: 0644]
src/flac/utils.h [new file with mode: 0644]
src/flac/vorbiscomment.c [new file with mode: 0644]
src/flac/vorbiscomment.h [new file with mode: 0644]
src/libFLAC++/Makefile.am [new file with mode: 0644]
src/libFLAC++/Makefile.lite [new file with mode: 0644]
src/libFLAC++/flac++.pc.in [new file with mode: 0644]
src/libFLAC++/libFLAC++.m4 [new file with mode: 0644]
src/libFLAC++/libFLAC++_dynamic.dsp [new file with mode: 0644]
src/libFLAC++/libFLAC++_dynamic.vcproj [new file with mode: 0644]
src/libFLAC++/libFLAC++_static.dsp [new file with mode: 0644]
src/libFLAC++/libFLAC++_static.vcproj [new file with mode: 0644]
src/libFLAC++/metadata.cpp [new file with mode: 0644]
src/libFLAC++/stream_decoder.cpp [new file with mode: 0644]
src/libFLAC++/stream_encoder.cpp [new file with mode: 0644]
src/libFLAC/Makefile.am [new file with mode: 0644]
src/libFLAC/Makefile.lite [new file with mode: 0644]
src/libFLAC/bitmath.c [new file with mode: 0644]
src/libFLAC/bitreader.c [new file with mode: 0644]
src/libFLAC/bitwriter.c [new file with mode: 0755]
src/libFLAC/cpu.c [new file with mode: 0644]
src/libFLAC/crc.c [new file with mode: 0644]
src/libFLAC/fixed.c [new file with mode: 0644]
src/libFLAC/flac.pc.in [new file with mode: 0644]
src/libFLAC/float.c [new file with mode: 0644]
src/libFLAC/format.c [new file with mode: 0644]
src/libFLAC/ia32/Makefile.am [new file with mode: 0644]
src/libFLAC/ia32/bitreader_asm.nasm [new file with mode: 0644]
src/libFLAC/ia32/cpu_asm.nasm [new file with mode: 0644]
src/libFLAC/ia32/fixed_asm.nasm [new file with mode: 0644]
src/libFLAC/ia32/lpc_asm.nasm [new file with mode: 0644]
src/libFLAC/ia32/nasm.h [new file with mode: 0644]
src/libFLAC/ia32/stream_encoder_asm.nasm [new file with mode: 0644]
src/libFLAC/include/Makefile.am [new file with mode: 0644]
src/libFLAC/include/private/Makefile.am [new file with mode: 0644]
src/libFLAC/include/private/all.h [new file with mode: 0644]
src/libFLAC/include/private/bitmath.h [new file with mode: 0644]
src/libFLAC/include/private/bitreader.h [new file with mode: 0644]
src/libFLAC/include/private/bitwriter.h [new file with mode: 0644]
src/libFLAC/include/private/cpu.h [new file with mode: 0644]
src/libFLAC/include/private/crc.h [new file with mode: 0644]
src/libFLAC/include/private/fixed.h [new file with mode: 0644]
src/libFLAC/include/private/float.h [new file with mode: 0644]
src/libFLAC/include/private/format.h [new file with mode: 0644]
src/libFLAC/include/private/lpc.h [new file with mode: 0644]
src/libFLAC/include/private/md5.h [new file with mode: 0644]
src/libFLAC/include/private/memory.h [new file with mode: 0644]
src/libFLAC/include/private/metadata.h [new file with mode: 0644]
src/libFLAC/include/private/ogg_decoder_aspect.h [new file with mode: 0644]
src/libFLAC/include/private/ogg_encoder_aspect.h [new file with mode: 0644]
src/libFLAC/include/private/ogg_helper.h [new file with mode: 0644]
src/libFLAC/include/private/ogg_mapping.h [new file with mode: 0644]
src/libFLAC/include/private/stream_encoder_framing.h [new file with mode: 0644]
src/libFLAC/include/private/window.h [new file with mode: 0644]
src/libFLAC/include/protected/Makefile.am [new file with mode: 0644]
src/libFLAC/include/protected/all.h [new file with mode: 0644]
src/libFLAC/include/protected/stream_decoder.h [new file with mode: 0644]
src/libFLAC/include/protected/stream_encoder.h [new file with mode: 0644]
src/libFLAC/libFLAC.m4 [new file with mode: 0644]
src/libFLAC/libFLAC_dynamic.dsp [new file with mode: 0644]
src/libFLAC/libFLAC_dynamic.vcproj [new file with mode: 0644]
src/libFLAC/libFLAC_static.dsp [new file with mode: 0644]
src/libFLAC/libFLAC_static.vcproj [new file with mode: 0644]
src/libFLAC/lpc.c [new file with mode: 0644]
src/libFLAC/md5.c [new file with mode: 0644]
src/libFLAC/memory.c [new file with mode: 0644]
src/libFLAC/metadata_iterators.c [new file with mode: 0644]
src/libFLAC/metadata_object.c [new file with mode: 0644]
src/libFLAC/ogg_decoder_aspect.c [new file with mode: 0644]
src/libFLAC/ogg_encoder_aspect.c [new file with mode: 0644]
src/libFLAC/ogg_helper.c [new file with mode: 0644]
src/libFLAC/ogg_mapping.c [new file with mode: 0644]
src/libFLAC/ppc/Makefile.am [new file with mode: 0644]
src/libFLAC/ppc/as/Makefile.am [new file with mode: 0644]
src/libFLAC/ppc/as/lpc_asm.s [new file with mode: 0644]
src/libFLAC/ppc/gas/Makefile.am [new file with mode: 0644]
src/libFLAC/ppc/gas/lpc_asm.s [new file with mode: 0644]
src/libFLAC/stream_decoder.c [new file with mode: 0644]
src/libFLAC/stream_encoder.c [new file with mode: 0644]
src/libFLAC/stream_encoder_framing.c [new file with mode: 0644]
src/libFLAC/window.c [new file with mode: 0644]
src/metaflac/Makefile.am [new file with mode: 0644]
src/metaflac/Makefile.lite [new file with mode: 0644]
src/metaflac/main.c [new file with mode: 0644]
src/metaflac/metaflac.dsp [new file with mode: 0644]
src/metaflac/metaflac.vcproj [new file with mode: 0644]
src/metaflac/operations.c [new file with mode: 0644]
src/metaflac/operations.h [new file with mode: 0644]
src/metaflac/operations_shorthand.h [new file with mode: 0644]
src/metaflac/operations_shorthand_cuesheet.c [new file with mode: 0644]
src/metaflac/operations_shorthand_picture.c [new file with mode: 0644]
src/metaflac/operations_shorthand_seektable.c [new file with mode: 0644]
src/metaflac/operations_shorthand_streaminfo.c [new file with mode: 0644]
src/metaflac/operations_shorthand_vorbiscomment.c [new file with mode: 0644]
src/metaflac/options.c [new file with mode: 0644]
src/metaflac/options.h [new file with mode: 0644]
src/metaflac/usage.c [new file with mode: 0644]
src/metaflac/usage.h [new file with mode: 0644]
src/metaflac/utils.c [new file with mode: 0644]
src/metaflac/utils.h [new file with mode: 0644]
src/monkeys_audio_utilities/Makefile.am [new file with mode: 0644]
src/monkeys_audio_utilities/flac_mac/Makefile.am [new file with mode: 0644]
src/monkeys_audio_utilities/flac_mac/flac_mac.dsp [new file with mode: 0644]
src/monkeys_audio_utilities/flac_mac/flac_mac.vcproj [new file with mode: 0644]
src/monkeys_audio_utilities/flac_mac/main.c [new file with mode: 0644]
src/monkeys_audio_utilities/flac_ren/Makefile.am [new file with mode: 0644]
src/monkeys_audio_utilities/flac_ren/flac_ren.dsp [new file with mode: 0644]
src/monkeys_audio_utilities/flac_ren/flac_ren.vcproj [new file with mode: 0644]
src/monkeys_audio_utilities/flac_ren/main.c [new file with mode: 0644]
src/plugin_common/Makefile.am [new file with mode: 0644]
src/plugin_common/Makefile.lite [new file with mode: 0644]
src/plugin_common/README [new file with mode: 0644]
src/plugin_common/all.h [new file with mode: 0644]
src/plugin_common/charset.c [new file with mode: 0644]
src/plugin_common/charset.h [new file with mode: 0644]
src/plugin_common/defs.h [new file with mode: 0644]
src/plugin_common/dither.c [new file with mode: 0644]
src/plugin_common/dither.h [new file with mode: 0644]
src/plugin_common/plugin_common_static.dsp [new file with mode: 0644]
src/plugin_common/plugin_common_static.vcproj [new file with mode: 0644]
src/plugin_common/replaygain.c [new file with mode: 0644]
src/plugin_common/replaygain.h [new file with mode: 0644]
src/plugin_common/tags.c [new file with mode: 0644]
src/plugin_common/tags.h [new file with mode: 0644]
src/plugin_winamp2/Makefile.am [new file with mode: 0644]
src/plugin_winamp2/configure.c [new file with mode: 0644]
src/plugin_winamp2/configure.h [new file with mode: 0644]
src/plugin_winamp2/in_flac.c [new file with mode: 0644]
src/plugin_winamp2/in_flac.dsp [new file with mode: 0644]
src/plugin_winamp2/in_flac.vcproj [new file with mode: 0644]
src/plugin_winamp2/include/Makefile.am [new file with mode: 0644]
src/plugin_winamp2/include/winamp2/Makefile.am [new file with mode: 0644]
src/plugin_winamp2/include/winamp2/in2.h [new file with mode: 0644]
src/plugin_winamp2/include/winamp2/out.h [new file with mode: 0644]
src/plugin_winamp2/infobox.c [new file with mode: 0644]
src/plugin_winamp2/infobox.h [new file with mode: 0644]
src/plugin_winamp2/playback.c [new file with mode: 0644]
src/plugin_winamp2/playback.h [new file with mode: 0644]
src/plugin_winamp2/resource.h [new file with mode: 0644]
src/plugin_winamp2/resource.rc [new file with mode: 0644]
src/plugin_winamp2/tagz.cpp [new file with mode: 0644]
src/plugin_winamp2/tagz.h [new file with mode: 0644]
src/plugin_xmms/Makefile.am [new file with mode: 0644]
src/plugin_xmms/Makefile.lite [new file with mode: 0644]
src/plugin_xmms/charset.c [new file with mode: 0644]
src/plugin_xmms/charset.h [new file with mode: 0644]
src/plugin_xmms/configure.c [new file with mode: 0644]
src/plugin_xmms/configure.h [new file with mode: 0644]
src/plugin_xmms/fileinfo.c [new file with mode: 0644]
src/plugin_xmms/http.c [new file with mode: 0644]
src/plugin_xmms/http.h [new file with mode: 0644]
src/plugin_xmms/locale_hack.h [new file with mode: 0644]
src/plugin_xmms/plugin.c [new file with mode: 0644]
src/plugin_xmms/plugin.h [new file with mode: 0644]
src/plugin_xmms/tag.c [new file with mode: 0644]
src/plugin_xmms/tag.h [new file with mode: 0644]
src/share/Makefile.am [new file with mode: 0644]
src/share/Makefile.lite [new file with mode: 0644]
src/share/README [new file with mode: 0644]
src/share/getopt/Makefile.am [new file with mode: 0644]
src/share/getopt/Makefile.lite [new file with mode: 0644]
src/share/getopt/getopt.c [new file with mode: 0644]
src/share/getopt/getopt1.c [new file with mode: 0644]
src/share/getopt/getopt_static.dsp [new file with mode: 0644]
src/share/getopt/getopt_static.vcproj [new file with mode: 0644]
src/share/grabbag/Makefile.am [new file with mode: 0644]
src/share/grabbag/Makefile.lite [new file with mode: 0644]
src/share/grabbag/cuesheet.c [new file with mode: 0644]
src/share/grabbag/file.c [new file with mode: 0644]
src/share/grabbag/grabbag_static.dsp [new file with mode: 0644]
src/share/grabbag/grabbag_static.vcproj [new file with mode: 0644]
src/share/grabbag/picture.c [new file with mode: 0644]
src/share/grabbag/replaygain.c [new file with mode: 0644]
src/share/grabbag/seektable.c [new file with mode: 0644]
src/share/replaygain_analysis/Makefile.am [new file with mode: 0644]
src/share/replaygain_analysis/Makefile.lite [new file with mode: 0644]
src/share/replaygain_analysis/replaygain_analysis.c [new file with mode: 0644]
src/share/replaygain_analysis/replaygain_analysis_static.dsp [new file with mode: 0644]
src/share/replaygain_analysis/replaygain_analysis_static.vcproj [new file with mode: 0644]
src/share/replaygain_synthesis/Makefile.am [new file with mode: 0644]
src/share/replaygain_synthesis/Makefile.lite [new file with mode: 0644]
src/share/replaygain_synthesis/include/Makefile.am [new file with mode: 0644]
src/share/replaygain_synthesis/include/private/Makefile.am [new file with mode: 0644]
src/share/replaygain_synthesis/include/private/fast_float_math_hack.h [new file with mode: 0644]
src/share/replaygain_synthesis/replaygain_synthesis.c [new file with mode: 0644]
src/share/replaygain_synthesis/replaygain_synthesis_static.dsp [new file with mode: 0644]
src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj [new file with mode: 0644]
src/share/utf8/Makefile.am [new file with mode: 0644]
src/share/utf8/Makefile.lite [new file with mode: 0644]
src/share/utf8/charmaps.h [new file with mode: 0644]
src/share/utf8/charset.c [new file with mode: 0644]
src/share/utf8/charset.h [new file with mode: 0644]
src/share/utf8/charset_test.c [new file with mode: 0644]
src/share/utf8/charsetmap.h [new file with mode: 0644]
src/share/utf8/iconvert.c [new file with mode: 0644]
src/share/utf8/iconvert.h [new file with mode: 0644]
src/share/utf8/makemap.c [new file with mode: 0644]
src/share/utf8/utf8.c [new file with mode: 0644]
src/share/utf8/utf8_static.dsp [new file with mode: 0644]
src/share/utf8/utf8_static.vcproj [new file with mode: 0644]
src/test_grabbag/Makefile.am [new file with mode: 0644]
src/test_grabbag/Makefile.lite [new file with mode: 0644]
src/test_grabbag/cuesheet/Makefile.am [new file with mode: 0644]
src/test_grabbag/cuesheet/Makefile.lite [new file with mode: 0644]
src/test_grabbag/cuesheet/main.c [new file with mode: 0644]
src/test_grabbag/cuesheet/test_cuesheet.dsp [new file with mode: 0644]
src/test_grabbag/cuesheet/test_cuesheet.vcproj [new file with mode: 0644]
src/test_grabbag/picture/Makefile.am [new file with mode: 0644]
src/test_grabbag/picture/Makefile.lite [new file with mode: 0644]
src/test_grabbag/picture/main.c [new file with mode: 0644]
src/test_grabbag/picture/test_picture.dsp [new file with mode: 0644]
src/test_grabbag/picture/test_picture.vcproj [new file with mode: 0644]
src/test_libFLAC++/Makefile.am [new file with mode: 0644]
src/test_libFLAC++/Makefile.lite [new file with mode: 0644]
src/test_libFLAC++/decoders.cpp [new file with mode: 0644]
src/test_libFLAC++/decoders.h [new file with mode: 0644]
src/test_libFLAC++/encoders.cpp [new file with mode: 0644]
src/test_libFLAC++/encoders.h [new file with mode: 0644]
src/test_libFLAC++/main.cpp [new file with mode: 0644]
src/test_libFLAC++/metadata.cpp [new file with mode: 0644]
src/test_libFLAC++/metadata.h [new file with mode: 0644]
src/test_libFLAC++/metadata_manip.cpp [new file with mode: 0644]
src/test_libFLAC++/metadata_object.cpp [new file with mode: 0644]
src/test_libFLAC++/test_libFLAC++.dsp [new file with mode: 0644]
src/test_libFLAC++/test_libFLAC++.vcproj [new file with mode: 0644]
src/test_libFLAC/Makefile.am [new file with mode: 0644]
src/test_libFLAC/Makefile.lite [new file with mode: 0644]
src/test_libFLAC/bitwriter.c [new file with mode: 0644]
src/test_libFLAC/bitwriter.h [new file with mode: 0644]
src/test_libFLAC/decoders.c [new file with mode: 0644]
src/test_libFLAC/decoders.h [new file with mode: 0644]
src/test_libFLAC/encoders.c [new file with mode: 0644]
src/test_libFLAC/encoders.h [new file with mode: 0644]
src/test_libFLAC/format.c [new file with mode: 0644]
src/test_libFLAC/format.h [new file with mode: 0644]
src/test_libFLAC/main.c [new file with mode: 0644]
src/test_libFLAC/metadata.c [new file with mode: 0644]
src/test_libFLAC/metadata.h [new file with mode: 0644]
src/test_libFLAC/metadata_manip.c [new file with mode: 0644]
src/test_libFLAC/metadata_object.c [new file with mode: 0644]
src/test_libFLAC/test_libFLAC.dsp [new file with mode: 0644]
src/test_libFLAC/test_libFLAC.vcproj [new file with mode: 0644]
src/test_libs_common/Makefile.am [new file with mode: 0644]
src/test_libs_common/Makefile.lite [new file with mode: 0644]
src/test_libs_common/README [new file with mode: 0644]
src/test_libs_common/file_utils_flac.c [new file with mode: 0644]
src/test_libs_common/metadata_utils.c [new file with mode: 0644]
src/test_libs_common/test_libs_common_static.dsp [new file with mode: 0644]
src/test_libs_common/test_libs_common_static.vcproj [new file with mode: 0644]
src/test_seeking/Makefile.am [new file with mode: 0644]
src/test_seeking/Makefile.lite [new file with mode: 0644]
src/test_seeking/main.c [new file with mode: 0644]
src/test_seeking/test_seeking.dsp [new file with mode: 0644]
src/test_seeking/test_seeking.vcproj [new file with mode: 0644]
src/test_streams/Makefile.am [new file with mode: 0644]
src/test_streams/Makefile.lite [new file with mode: 0644]
src/test_streams/main.c [new file with mode: 0644]
src/test_streams/test_streams.dsp [new file with mode: 0644]
src/test_streams/test_streams.vcproj [new file with mode: 0644]
strip_non_asm_libtool_args.sh [new file with mode: 0755]
test/Makefile.am [new file with mode: 0644]
test/Makefile.lite [new file with mode: 0644]
test/cuesheet.ok [new file with mode: 0644]
test/cuesheets/Makefile.am [new file with mode: 0644]
test/cuesheets/bad.000.CATALOG_multiple.cue [new file with mode: 0644]
test/cuesheets/bad.001.CATALOG_missing_number.cue [new file with mode: 0644]
test/cuesheets/bad.002.CATALOG_number_too_long.cue [new file with mode: 0644]
test/cuesheets/bad.003.CATALOG_not_13_digits.cue [new file with mode: 0644]
test/cuesheets/bad.030.FLAGS_multiple.cue [new file with mode: 0644]
test/cuesheets/bad.031.FLAGS_wrong_place_1.cue [new file with mode: 0644]
test/cuesheets/bad.032.FLAGS_wrong_place_2.cue [new file with mode: 0644]
test/cuesheets/bad.060.INDEX_wrong_place.cue [new file with mode: 0644]
test/cuesheets/bad.061.INDEX_missing_number.cue [new file with mode: 0644]
test/cuesheets/bad.062.INDEX_invalid_number_1.cue [new file with mode: 0644]
test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue [new file with mode: 0644]
test/cuesheets/bad.064.INDEX_num_non_sequential.cue [new file with mode: 0644]
test/cuesheets/bad.065.INDEX_num_out_of_range.cue [new file with mode: 0644]
test/cuesheets/bad.066.INDEX_missing_offset.cue [new file with mode: 0644]
test/cuesheets/bad.067.INDEX_illegal_offset.cue [new file with mode: 0644]
test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue [new file with mode: 0644]
test/cuesheets/bad.069.nonzero_first_INDEX.cue [new file with mode: 0644]
test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue [new file with mode: 0644]
test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue [new file with mode: 0644]
test/cuesheets/bad.110.ISRC_multiple.cue [new file with mode: 0644]
test/cuesheets/bad.111.ISRC_wrong_place_1.cue [new file with mode: 0644]
test/cuesheets/bad.112.ISRC_wrong_place_2.cue [new file with mode: 0644]
test/cuesheets/bad.113.ISRC_missing_number.cue [new file with mode: 0644]
test/cuesheets/bad.114.ISRC_invalid_number.cue [new file with mode: 0644]
test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue [new file with mode: 0644]
test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue [new file with mode: 0644]
test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue [new file with mode: 0644]
test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue [new file with mode: 0644]
test/cuesheets/bad.134.TRACK_missing_number.cue [new file with mode: 0644]
test/cuesheets/bad.135.TRACK_invalid_number_1.cue [new file with mode: 0644]
test/cuesheets/bad.136.TRACK_invalid_number_2.cue [new file with mode: 0644]
test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue [new file with mode: 0644]
test/cuesheets/bad.138.TRACK_num_non_sequential.cue [new file with mode: 0644]
test/cuesheets/bad.139.TRACK_missing_type.cue [new file with mode: 0644]
test/cuesheets/bad.140.no_TRACKs.cue [new file with mode: 0644]
test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue [new file with mode: 0644]
test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue [new file with mode: 0644]
test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue [new file with mode: 0644]
test/cuesheets/bad.230.FLAC_leadout_multiple.cue [new file with mode: 0644]
test/cuesheets/bad.231.FLAC_leadout_missing_track.cue [new file with mode: 0644]
test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue [new file with mode: 0644]
test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue [new file with mode: 0644]
test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue [new file with mode: 0644]
test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue [new file with mode: 0644]
test/cuesheets/good.000.cue [new file with mode: 0644]
test/cuesheets/good.001.cue [new file with mode: 0644]
test/cuesheets/good.002.dos_format.cue [new file with mode: 0644]
test/cuesheets/good.003.missing_final_newline.cue [new file with mode: 0644]
test/cuesheets/good.004.dos_format.missing_final_newline.cue [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/Makefile.am [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case00a-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case01a-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case01b-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case01c-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case01d-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case01e-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case02a-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case02b-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case02c-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case03a-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case03b-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case03c-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case04a-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case04b-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case04c-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case04d-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/case04e-expect.meta [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-SCPAP.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-SCVA.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-SCVAUP.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-SCVPAP.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-SVAUP.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input-VA.flac [new file with mode: 0644]
test/flac-to-flac-metadata-test-files/input0.cue [new file with mode: 0644]
test/metaflac-test-files/Makefile.am [new file with mode: 0644]
test/metaflac-test-files/case00-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case01-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case02-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case03-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case04-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case05-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case06-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case07-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case08-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case09-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case10-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case11-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case12-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case13-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case14-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case15-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case16-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case17-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case18-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case19-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case20-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case21-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case22-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case23-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case24-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case25-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case26-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case27-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case28-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case29-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case30-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case31-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case32-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case33-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case34-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case35-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case36-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case37-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case38-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case39-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case40-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case41-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case42-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case43-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case44-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case45-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case46-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case47-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case48-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case49-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case50-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case51-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case52-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case53-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case54-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case55-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case56-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case57-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case58-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case59-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case60-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case61-expect.meta [new file with mode: 0644]
test/metaflac-test-files/case62-expect.meta [new file with mode: 0644]
test/metaflac.flac.in [new file with mode: 0644]
test/metaflac.flac.ok [new file with mode: 0644]
test/picture.ok [new file with mode: 0644]
test/pictures/0.gif [new file with mode: 0644]
test/pictures/0.jpg [new file with mode: 0644]
test/pictures/0.png [new file with mode: 0644]
test/pictures/1.gif [new file with mode: 0644]
test/pictures/1.png [new file with mode: 0644]
test/pictures/2.gif [new file with mode: 0644]
test/pictures/2.png [new file with mode: 0644]
test/pictures/3.png [new file with mode: 0644]
test/pictures/4.jpg [new file with mode: 0644]
test/pictures/4.png [new file with mode: 0644]
test/pictures/5.png [new file with mode: 0644]
test/pictures/6.png [new file with mode: 0644]
test/pictures/7.png [new file with mode: 0644]
test/pictures/8.png [new file with mode: 0644]
test/pictures/Makefile.am [new file with mode: 0644]
test/test_bins.sh [new file with mode: 0755]
test/test_flac.sh [new file with mode: 0755]
test/test_grabbag.sh [new file with mode: 0755]
test/test_libFLAC++.sh [new file with mode: 0755]
test/test_libFLAC.sh [new file with mode: 0755]
test/test_metaflac.sh [new file with mode: 0755]
test/test_seeking.sh [new file with mode: 0755]
test/test_streams.sh [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..217baf4
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,41 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This file is part the FLAC project.  FLAC is comprised of several
+ * components distributed under difference licenses.  The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution).  All other programs, libraries, and
+ * plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+ * is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+ * FLAC distribution contains at the top the terms under which it may be
+ * distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above.  See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+
+FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio
+codec developed by Josh Coalson <jcoalson@users.sourceforge.net>.
+
+Other major contributors and their contributions:
+"Andrey Astafiev" <andrei@tvcell.ru>
+* Russian translation of the HTML documentation
+
+"Miroslav Lichvar" <lichvarm@phoenix.inf.upol.cz>
+* IA-32 assembly versions of several libFLAC routines
+
+"Brady Patterson" <bpat@users.sourceforge.net>
+* AIFF file support, PPC assembly versions of libFLAC routines
+
+"Daisuke Shimamura" <Daisuke_Shimamura@nifty.com>
+* i18n support in the XMMS plugin
+
+"X-Fixer" <x-fixer@narod.ru>
+* Configuration system, tag editing, and file info in the Winamp2 plugin
+
+"Matt Zimmerman" <mdz@debian.org>
+* Libtool/autoconf/automake make system, flac man page
+
diff --git a/COPYING.FDL b/COPYING.FDL
new file mode 100644 (file)
index 0000000..4a0fe1c
--- /dev/null
@@ -0,0 +1,397 @@
+               GNU Free Documentation License
+                 Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject.  (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License.  Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License.  However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.2
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644 (file)
index 0000000..c3c7a9e
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644 (file)
index 0000000..5ab7695
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/COPYING.Xiph b/COPYING.Xiph
new file mode 100644 (file)
index 0000000..0a104a9
--- /dev/null
@@ -0,0 +1,28 @@
+Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/FLAC.dsw b/FLAC.dsw
new file mode 100644 (file)
index 0000000..c2e338a
--- /dev/null
+++ b/FLAC.dsw
@@ -0,0 +1,683 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "all"=.\all.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name all_dynamic\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name all_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "all_dynamic"=.\all_dynamic.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name examples\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name iffscan\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name metaflac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name in_flac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac_mac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac_ren\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flacdiff\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flactimer\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_analysis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_synthesis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name getopt_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_dynamic\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_dynamic\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libs_common_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name plugin_common_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name utf8_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_cuesheet\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_picture\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libFLAC\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libFLAC++\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_seeking\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_streams\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "all_static"=.\all_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name examples\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name iffscan\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name metaflac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name in_flac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac_mac\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flac_ren\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flacdiff\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name flactimer\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_analysis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_synthesis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name getopt_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libs_common_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name plugin_common_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name utf8_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_cuesheet\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_picture\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libFLAC\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libFLAC++\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_seeking\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_streams\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "examples"=.\examples\examples.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name example_c_decode_file\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name example_c_encode_file\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name example_cpp_decode_file\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name example_cpp_encode_file\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "example_c_decode_file"=.\examples\c\decode\file\example_c_decode_file.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "example_c_encode_file"=.\examples\c\encode\file\example_c_encode_file.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "example_cpp_decode_file"=.\examples\cpp\decode\file\example_cpp_decode_file.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "example_cpp_encode_file"=.\examples\cpp\encode\file\example_cpp_encode_file.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "flac"=.\src\flac\flac.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_analysis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_synthesis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name getopt_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name utf8_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "iffscan"=.\src\flac\iffscan.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "flac_mac"=.\src\monkeys_audio_utilities\flac_mac\flac_mac.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "flac_ren"=.\src\monkeys_audio_utilities\flac_ren\flac_ren.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "replaygain_analysis_static"=.\src\share\replaygain_analysis\replaygain_analysis_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "replaygain_synthesis_static"=.\src\share\replaygain_synthesis\replaygain_synthesis_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "getopt_static"=.\src\share\getopt\getopt_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "grabbag_static"=.\src\share\grabbag\grabbag_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_analysis_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "in_flac"=.\src\plugin_winamp2\in_flac.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name plugin_common_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "libFLAC_dynamic"=.\src\libFLAC\libFLAC_dynamic.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "libFLAC_static"=.\src\libFLAC\libFLAC_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "libFLAC++_dynamic"=".\src\libFLAC++\libFLAC++_dynamic.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_dynamic\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "libFLAC++_static"=".\src\libFLAC++\libFLAC++_static.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "metaflac"=.\src\metaflac\metaflac.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_analysis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name getopt_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name utf8_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "plugin_common_static"=.\src\plugin_common\plugin_common_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name replaygain_synthesis_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_cuesheet"=.\src\test_grabbag\cuesheet\test_cuesheet.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_picture"=.\src\test_grabbag\picture\test_picture.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name grabbag_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_libs_common"=.\src\test_libs_common\test_libs_common_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_libFLAC"=.\src\test_libFLAC\test_libFLAC.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libs_common_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_libFLAC++"=".\src\test_libFLAC++\test_libFLAC++.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name test_libs_common_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_seeking"=.\src\test_seeking\test_seeking.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "test_streams"=.\src\test_streams\test_streams.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "utf8_static"=.\src\share\utf8\utf8_static.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "flacdiff"=".\src\utils\flacdiff\flacdiff.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libFLAC++_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "flactimer"=".\src\utils\flactimer\flactimer.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/FLAC.sln b/FLAC.sln
new file mode 100644 (file)
index 0000000..e427c25
--- /dev/null
+++ b/FLAC.sln
@@ -0,0 +1,265 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 9.00\r
+# Visual C++ Express 2005\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "example_c_decode_file", "examples\c\decode\file\example_c_decode_file.vcproj", "{4cefbd00-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "example_c_encode_file", "examples\c\encode\file\example_c_encode_file.vcproj", "{4cefbd01-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "example_cpp_decode_file", "examples\cpp\decode\file\example_cpp_decode_file.vcproj", "{4cefbe00-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+               {4cefbc86-c215-11db-8314-0800200c9a66} = {4cefbc86-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "example_cpp_encode_file", "examples\cpp\encode\file\example_cpp_encode_file.vcproj", "{4cefbe01-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+               {4cefbc86-c215-11db-8314-0800200c9a66} = {4cefbc86-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "flac", "src\flac\flac.vcproj", "{4cefbc7d-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+               {4cefbc89-c215-11db-8314-0800200c9a66} = {4cefbc89-c215-11db-8314-0800200c9a66}\r
+               {4cefbc92-c215-11db-8314-0800200c9a66} = {4cefbc92-c215-11db-8314-0800200c9a66}\r
+               {4cefbc80-c215-11db-8314-0800200c9a66} = {4cefbc80-c215-11db-8314-0800200c9a66}\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66} = {4cefbc8a-c215-11db-8314-0800200c9a66}\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "iffscan", "src\flac\iffscan.vcproj", "{4cefbc94-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "flac_mac", "src\monkeys_audio_utilities\flac_mac\flac_mac.vcproj", "{4cefbc7e-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "flac_ren", "src\monkeys_audio_utilities\flac_ren\flac_ren.vcproj", "{4cefbc7f-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "flacdiff", "src\utils\flacdiff\flacdiff.vcproj", "{4cefbc93-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc86-c215-11db-8314-0800200c9a66} = {4cefbc86-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "flactimer", "src\utils\flactimer\flactimer.vcproj", "{4cefbc95-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "getopt_static", "src\share\getopt\getopt_static.vcproj", "{4cefbc80-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "grabbag_static", "src\share\grabbag\grabbag_static.vcproj", "{4cefbc81-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+               {4cefbc89-c215-11db-8314-0800200c9a66} = {4cefbc89-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "in_flac", "src\plugin_winamp2\in_flac.vcproj", "{4cefbc82-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66} = {4cefbc8a-c215-11db-8314-0800200c9a66}\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+               {4cefbc88-c215-11db-8314-0800200c9a66} = {4cefbc88-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "libFLAC_dynamic", "src\libFLAC\libFLAC_dynamic.vcproj", "{4cefbc83-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "libFLAC_static", "src\libFLAC\libFLAC_static.vcproj", "{4cefbc84-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "libFLAC++_dynamic", "src\libFLAC++\libFLAC++_dynamic.vcproj", "{4cefbc85-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc83-c215-11db-8314-0800200c9a66} = {4cefbc83-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "libFLAC++_static", "src\libFLAC++\libFLAC++_static.vcproj", "{4cefbc86-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "metaflac", "src\metaflac\metaflac.vcproj", "{4cefbc87-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+               {4cefbc80-c215-11db-8314-0800200c9a66} = {4cefbc80-c215-11db-8314-0800200c9a66}\r
+               {4cefbc92-c215-11db-8314-0800200c9a66} = {4cefbc92-c215-11db-8314-0800200c9a66}\r
+               {4cefbc89-c215-11db-8314-0800200c9a66} = {4cefbc89-c215-11db-8314-0800200c9a66}\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "plugin_common_static", "src\plugin_common\plugin_common_static.vcproj", "{4cefbc88-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "replaygain_analysis_static", "src\share\replaygain_analysis\replaygain_analysis_static.vcproj", "{4cefbc89-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "replaygain_synthesis_static", "src\share\replaygain_synthesis\replaygain_synthesis_static.vcproj", "{4cefbc8a-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_cuesheet", "src\test_grabbag\cuesheet\test_cuesheet.vcproj", "{4cefbc8b-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_libFLAC", "src\test_libFLAC\test_libFLAC.vcproj", "{4cefbc8c-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66} = {4cefbc8e-c215-11db-8314-0800200c9a66}\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_libFLAC++", "src\test_libFLAC++\test_libFLAC++.vcproj", "{4cefbc8d-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc86-c215-11db-8314-0800200c9a66} = {4cefbc86-c215-11db-8314-0800200c9a66}\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66} = {4cefbc8e-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_libs_common_static", "src\test_libs_common\test_libs_common_static.vcproj", "{4cefbc8e-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_picture", "src\test_grabbag\picture\test_picture.vcproj", "{4cefbc8f-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc81-c215-11db-8314-0800200c9a66} = {4cefbc81-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_seeking", "src\test_seeking\test_seeking.vcproj", "{4cefbc90-c215-11db-8314-0800200c9a66}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {4cefbc84-c215-11db-8314-0800200c9a66} = {4cefbc84-c215-11db-8314-0800200c9a66}\r
+       EndProjectSection\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "test_streams", "src\test_streams\test_streams.vcproj", "{4cefbc91-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Project("{4cefbc7c-c215-11db-8314-0800200c9a66}") = "utf8_static", "src\share\utf8\utf8_static.vcproj", "{4cefbc92-c215-11db-8314-0800200c9a66}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Release|Win32 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {4cefbc7d-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc7d-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc7d-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc7d-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc7e-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc7e-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc7e-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc7e-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc7f-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc7f-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc7f-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc7f-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc80-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc80-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc80-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc80-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc81-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc81-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc81-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc81-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc82-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc82-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc82-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc82-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc83-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc83-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc83-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc83-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc84-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc84-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc84-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc84-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc85-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc85-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc85-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc85-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc86-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc86-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc86-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc86-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc87-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc87-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc87-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc87-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc88-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc88-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc88-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc88-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc89-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc89-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc89-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc89-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8a-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8b-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8b-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8b-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8b-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8c-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8c-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8c-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8c-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8d-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8d-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8d-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8d-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8e-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc8f-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc8f-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc8f-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc8f-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc90-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc90-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc90-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc90-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc91-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc91-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc91-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc91-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc92-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc92-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc92-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc92-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc93-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc93-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc93-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc93-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc94-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc94-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc94-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc94-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbc95-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbc95-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbc95-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbc95-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbd00-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbd00-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbd00-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbd00-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbd01-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbd01-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbd01-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbd01-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbe00-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbe00-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbe00-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbe00-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+               {4cefbe01-c215-11db-8314-0800200c9a66}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4cefbe01-c215-11db-8314-0800200c9a66}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4cefbe01-c215-11db-8314-0800200c9a66}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4cefbe01-c215-11db-8314-0800200c9a66}.Release|Win32.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..28ae291
--- /dev/null
@@ -0,0 +1,52 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# automake provides the following useful targets:
+#
+# all: build all programs and libraries using the current
+# configuration (set by configure)
+#
+# check: build and run all self-tests
+#
+# clean: remove everything except what's required to build everything
+#
+# distclean: remove everything except what goes in the distribution
+#
+
+AUTOMAKE_OPTIONS = foreign 1.7
+
+##SUBDIRS = doc include m4 man src examples test build obj
+SUBDIRS = include m4 man src examples
+DISTCLEANFILES = libtool-disable-static
+
+EXTRA_DIST = \
+       COPYING.FDL \
+       COPYING.GPL \
+       COPYING.LGPL \
+       COPYING.Xiph \
+       FLAC.dsw \
+       FLAC.sln \
+       Makefile.lite \
+       all.dsp \
+       all_dynamic.dsp \
+       all_static.dsp \
+       autogen.sh \
+       config.rpath \
+       depcomp \
+       ltmain.sh \
+       strip_non_asm_libtool_args.sh
diff --git a/Makefile.lite b/Makefile.lite
new file mode 100644 (file)
index 0000000..92e5822
--- /dev/null
@@ -0,0 +1,106 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU Makefile
+#
+# Useful targets
+#
+# all     : build all libraries and programs in the default configuration (currently 'release')
+# debug   : build all libraries and programs in debug mode
+# valgrind: build all libraries and programs in debug mode, dynamically linked and ready for valgrind
+# release : build all libraries and programs in release mode
+# test    : run the unit and stream tests
+# clean   : remove all non-distro files
+#
+
+topdir = .
+
+.PHONY: all doc src examples libFLAC libFLAC++ share plugin_common plugin_xmms flac metaflac test_grabbag test_libFLAC test_libFLAC++ test_seeking test_streams
+all: doc src examples
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+doc:
+       (cd $@ && $(MAKE) -f Makefile.lite)
+
+src:
+       (cd $@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+examples: src
+       (cd $@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+libFLAC:
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+libFLAC++: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+share: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+flac: libFLAC share
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+metaflac: libFLAC share
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+plugin_common: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+plugin_xmms: libFLAC plugin_common
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_seeking: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_streams: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_grabbag: share
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_libFLAC: libFLAC
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test_libFLAC++: libFLAC libFLAC++
+       (cd src/$@ && $(MAKE) -f Makefile.lite $(CONFIG))
+
+test: debug
+       (cd test && $(MAKE) -f Makefile.lite debug)
+
+testv: valgrind
+       (cd test && $(MAKE) -f Makefile.lite valgrind)
+
+testr: release
+       (cd test && $(MAKE) -f Makefile.lite release)
+
+clean:
+       -(cd doc && $(MAKE) -f Makefile.lite clean)
+       -(cd src && $(MAKE) -f Makefile.lite clean)
+       -(cd examples && $(MAKE) -f Makefile.lite clean)
+       -(cd test && $(MAKE) -f Makefile.lite clean)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f4a461b
--- /dev/null
+++ b/README
@@ -0,0 +1,254 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This file is part the FLAC project.  FLAC is comprised of several
+ * components distributed under difference licenses.  The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution).  All other programs, libraries, and
+ * plugins are distributed under the LGPL or GPL (see COPYING.LGPL and
+ * COPYING.GPL).  The documentation is distributed under the Gnu FDL (see
+ * COPYING.FDL).  Each file in the FLAC distribution contains at the top the
+ * terms under which it may be distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above.  See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+
+FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio
+codec developed by Josh Coalson.
+
+FLAC is comprised of
+  * `libFLAC', a library which implements reference encoders and
+    decoders for native FLAC and Ogg FLAC, and a metadata interface
+  * `libFLAC++', a C++ object wrapper library around libFLAC
+  * `flac', a command-line program for encoding and decoding files
+  * `metaflac', a command-line program for viewing and editing FLAC
+    metadata
+  * player plugins for XMMS and Winamp
+  * user and API documentation
+
+The libraries (libFLAC, libFLAC++) are
+licensed under Xiph.org's BSD-like license (see COPYING.Xiph).  All other
+programs and plugins are licensed under the GNU General Public License
+(see COPYING.GPL).  The documentation is licensed under the GNU Free
+Documentation License (see COPYING.FDL).
+
+
+===============================================================================
+FLAC - 1.2.1 - Contents
+===============================================================================
+
+- Introduction
+- Prerequisites
+- Note to embedded developers
+- Building in a GNU environment
+- Building with Makefile.lite
+- Building with MSVC
+- Building on Mac OS X
+
+
+===============================================================================
+Introduction
+===============================================================================
+
+This is the source release for the FLAC project.  See
+
+       doc/html/index.html
+
+for full documentation.
+
+A brief description of the directory tree:
+
+       doc/          the HTML documentation
+       include/      public include files for libFLAC and libFLAC++
+       man/          the man page for `flac'
+       src/          the source code and private headers
+       test/         the test scripts
+
+
+===============================================================================
+Prerequisites
+===============================================================================
+
+To build FLAC with support for Ogg FLAC you must have built and installed
+libogg according to the specific instructions below.  You must have
+libogg 1.1.2 or greater, or there will be seeking problems with Ogg FLAC.
+
+If you are building on x86 and want the assembly optimizations, you will
+need to have NASM >= 0.98.30 installed according to the specific instructions
+below.
+
+
+===============================================================================
+Note to embedded developers
+===============================================================================
+
+libFLAC has grown larger over time as more functionality has been
+included, but much of it may be unnecessary for a particular embedded
+implementation.  Unused parts may be pruned by some simple editing of
+configure.in and src/libFLAC/Makefile.am; the following dependency
+graph shows which modules may be pruned without breaking things
+further down:
+
+metadata.h
+       stream_decoder.h
+       format.h
+
+stream_encoder.h
+       stream_decoder.h
+       format.h
+
+stream_decoder.h
+       format.h
+
+In other words, for pure decoding applications, both the stream encoder
+and metadata editing interfaces can be safely removed.
+
+There is a section dedicated to embedded use in the libFLAC API
+HTML documentation (see doc/html/api/index.html).
+
+Also, there are several places in the libFLAC code with comments marked
+with "OPT:" where a #define can be changed to enable code that might be
+faster on a specific platform.  Experimenting with these can yield faster
+binaries.
+
+
+===============================================================================
+Building in a GNU environment
+===============================================================================
+
+FLAC uses autoconf and libtool for configuring and building.
+Better documentation for these will be forthcoming, but in
+general, this should work:
+
+./configure && make && make check && make install
+
+The 'make check' step is optional; omit it to skip all the tests,
+which can take several hours and use around 70-80 megs of disk space.
+Even though it will stop with an explicit message on any failure, it
+does print out a lot of stuff so you might want to capture the output
+to a file if you're having a problem.  Also, don't run 'make check'
+as root because it confuses some of the tests.
+
+NOTE: Despite our best efforts it's entirely possible to have
+problems when using older versions of autoconf, automake, or
+libtool.  If you have the latest versions and still can't get it
+to work, see the next section on Makefile.lite.
+
+There are a few FLAC-specific arguments you can give to
+`configure':
+
+--enable-debug : Builds everything with debug symbols and some
+extra (and more verbose) error checking.
+
+--disable-asm-optimizations : Disables the compilation of the
+assembly routines.  Many routines have assembly versions for
+speed and `configure' is pretty good about knowing what is
+supported, but you can use this option to build only from the
+C sources.  May be necessary for building on OS X (Intel)
+
+--enable-sse : If you are building for an x86 CPU that supports
+SSE instructions, you can enable some of the faster routines
+if your operating system also supports SSE instructions.  flac
+can tell if the CPU supports the instructions but currently has
+no way to test if the OS does, so if it does, you must pass
+this argument to configure to use the SSE routines.  If flac
+crashes when built with this option you will have to go back and
+configure without --enable-sse.  Note that
+--disable-asm-optimizations implies --disable-sse.
+
+--enable-local-xmms-plugin : Installs the FLAC XMMS plugin in
+$HOME/.xmms/Plugins, instead of the global XMMS plugin area
+(usually /usr/lib/xmms/Input).
+
+--with-ogg=
+--with-xmms-prefix=
+--with-libiconv-prefix=
+Use these if you have these packages but configure can't find them.
+
+If you want to build completely from scratch (i.e. starting with just
+configure.in and Makefile.am) you should be able to just run 'autogen.sh'
+but make sure and read the comments in that file first.
+
+
+===============================================================================
+Building with Makefile.lite
+===============================================================================
+
+There is a more lightweight build system for do-it-yourself-ers.
+It is also useful if configure isn't working, which may be the
+case since lately we've had some problems with different versions
+of automake and libtool.  The Makefile.lite system should work
+on GNU systems with few or no adjustments.
+
+From the top level just 'make -f Makefile.lite'.  You can
+specify zero or one optional target from 'release', 'debug',
+'test', or 'clean'.  The default is 'release'.  There is no
+'install' target but everything you need will end up in the
+obj/ directory.
+
+If you are not on an x86 system or you don't have nasm, you
+may have to change the DEFINES in src/libFLAC/Makefile.lite.  If
+you don't have nasm, remove -DFLAC__HAS_NASM.  If your target is
+not an x86, change -DFLAC__CPU_IA32 to -DFLAC__CPU_UNKNOWN.
+
+
+===============================================================================
+Building with MSVC
+===============================================================================
+
+There are .dsp projects and a master FLAC.dsw workspace to build all
+the libraries and executables with MSVC6.  There are also .vcproj
+projects and a master FLAC.sln solution to build all the libraries and
+executables with VC++ 2005.
+
+Prerequisite: you must have the Ogg libraries installed as described
+later.
+
+Prerequisite: you must have nasm installed, and nasmw.exe must be in
+your PATH, or the path to nasmw.exe must be added to the list of
+directories for executable files in the MSVC global options.
+
+MSVC6:
+To build everything, run Developer Studio, do File|Open Workspace,
+and open FLAC.dsw.  Select "Build | Set active configuration..."
+from the menu, then in the dialog, select "All - Win32 Release" (or
+Debug if you prefer).  Click "Ok" then hit F7 to build.
+
+VC++ 2005:
+To build everything, run Visual Studio, do File|Open and open FLAC.sln.
+From the dropdown in the toolbar, select "Release" instead of "Debug",
+then hit F7 to build.
+
+Either way, this will build all libraries both statically (e.g.
+obj\release\lib\libFLAC_static.lib) and as DLLs (e.g.
+obj\release\lib\libFLAC.dll), and it will build all binaries, statically
+linked (e.g. obj\release\bin\flac.exe).
+
+Everything will end up in the "obj" directory.  DLLs and .exe files
+are all that are needed and can be copied to an installation area and
+added to the PATH.  The plugins have to be copied to their appropriate
+place in the player area.  For Winamp2 this is <winamp2-dir>\Plugins.
+
+By default the code is configured with Ogg support.  Before building FLAC
+you will need to get the Ogg source distribution
+(see http://xiph.org/ogg/vorbis/download/), build ogg_static.lib (load and
+build win32\ogg_static.dsp), copy ogg_static.lib into FLAC's
+'obj\release\lib' directory, and copy the entire include\ogg tree into
+FLAC's 'include' directory (so that there is an 'ogg' directory in FLAC's
+'include' directory with the files ogg.h, os_types.h and config_types.h).
+
+If you want to build without Ogg support, instead edit all .dsp or
+.vcproj files and remove any occurrences of "/D FLAC__HAS_OGG".
+
+
+===============================================================================
+Building on Mac OS X
+===============================================================================
+
+If you have Fink or a recent version of OS X with the proper autotooles,
+the GNU flow above should work.  The Project Builder project has been
+deprecated but we are working on replacing it with an Xcode equivalent.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..19b724e
--- /dev/null
@@ -0,0 +1,8287 @@
+# generated automatically by aclocal 1.7.9 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Do all the work for Automake.                            -*- Autoconf -*-
+
+# This macro actually does too much some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 10
+
+AC_PREREQ([2.54])
+
+# Autoconf 2.50 wants to disallow AM_ names.  We explicitly allow
+# the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+ AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+   test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_MISSING_PROG(AMTAR, tar)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+                  [_AM_DEPENDENCIES(CC)],
+                  [define([AC_PROG_CC],
+                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                  [_AM_DEPENDENCIES(CXX)],
+                  [define([AC_PROG_CXX],
+                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $1 | $1:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# Copyright 2002  Free Software Foundation, Inc.
+
+# 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, 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
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.7"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+        [AM_AUTOMAKE_VERSION([1.7.9])])
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+
+# Copyright 2001, 2002  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 2
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 3
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+#  -*- Autoconf -*-
+
+
+# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 3
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# AM_AUX_DIR_EXPAND
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+# Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])
+
+AC_DEFUN([AM_AUX_DIR_EXPAND], [
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# AM_PROG_INSTALL_STRIP
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+#                                                          -*- Autoconf -*-
+# Copyright (C) 2003  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 1
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# serial 5                                             -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003  Free Software Foundation, Inc.
+
+# 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, 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.
+
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      : > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored.
+      if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking Speeds up one-time builds
+  --enable-dependency-tracking  Do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking.   -*- Autoconf -*-
+
+# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+# 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, 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.
+
+#serial 2
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+  # Strip MF so we end up with the name of the file.
+  mf=`echo "$mf" | sed -e 's/:.*$//'`
+  # Check whether this is an Automake generated Makefile or not.
+  # We used to match only the files named `Makefile.in', but
+  # some people rename them; so instead we look at the file content.
+  # Grep'ing the first line is not enough: some people post-process
+  # each Makefile.in and add a new line on top of each file to say so.
+  # So let's grep whole file.
+  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+    dirpart=`AS_DIRNAME("$mf")`
+  else
+    continue
+  fi
+  grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue
+  # Extract the definition of DEP_FILES from the Makefile without
+  # running `make'.
+  DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
+  test -z "$DEPDIR" && continue
+  # When using ansi2knr, U may be empty or an underscore; expand it
+  U=`sed -n -e '/^U = / s///p' < "$mf"`
+  test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
+  # We invoke sed twice because it is the simplest approach to
+  # changing $(DEPDIR) to its actual value in the expansion.
+  for file in `sed -n -e '
+    /^DEP_FILES = .*\\\\$/ {
+      s/^DEP_FILES = //
+      :loop
+       s/\\\\$//
+       p
+       n
+       /\\\\$/ b loop
+      p
+    }
+    /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
+       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+    # Make sure the directory exists.
+    test -f "$dirpart/$file" && continue
+    fdir=`AS_DIRNAME(["$file"])`
+    AS_MKDIR_P([$dirpart/$fdir])
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Check to see how 'make' treats includes.     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 2
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+       @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# AM_CONDITIONAL                                              -*- Autoconf -*-
+
+# Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 5
+
+AC_PREREQ(2.52)
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+        [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.])
+fi])])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# Copyright 1996, 1998, 2000, 2001, 2002  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 2
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode is disabled by default
+  AC_ARG_ENABLE(maintainer-mode,
+[  --enable-maintainer-mode enable make rules and dependencies not useful
+                          (and sometimes confusing) to the casual installer],
+      USE_MAINTAINER_MODE=$enableval,
+      USE_MAINTAINER_MODE=no)
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+
+# serial 47 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+         [],
+         [m4_define([AC_PROVIDE_IFELSE],
+                [m4_ifdef([AC_PROVIDE_$1],
+                          [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+    [AC_LIBTOOL_CXX],
+    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+  ])])
+dnl And a similar setup for Fortran 77 support
+  AC_PROVIDE_IFELSE([AC_PROG_F77],
+    [AC_LIBTOOL_F77],
+    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+    [AC_LIBTOOL_GCJ],
+    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+      [AC_LIBTOOL_GCJ],
+      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+       [AC_LIBTOOL_GCJ],
+      [ifdef([AC_PROG_GCJ],
+            [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([A][M_PROG_GCJ],
+            [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([LT_AC_PROG_GCJ],
+            [define([LT_AC_PROG_GCJ],
+               defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+    ;;
+  *)
+    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    AC_PATH_MAGIC
+  fi
+  ;;
+esac
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+    [AC_HELP_STRING([--with-pic],
+       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_LINKER_BOILERPLATE
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+            [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+        [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+  ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+[$]*
+EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+       echo_test_string="`eval $cmd`" &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+    then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+   test "X$echo_testing_string" = "X$echo_test_string"; then
+  :
+else
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+        test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running configure again with it.
+      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+    else
+      # Try using printf.
+      echo='printf %s\n'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+        echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+        test "X$echo_testing_string" = "X$echo_test_string"; then
+       # Cool, printf works
+       :
+      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+          test "X$echo_testing_string" = 'X\t' &&
+          echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+          test "X$echo_testing_string" = "X$echo_test_string"; then
+       CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+       export CONFIG_SHELL
+       SHELL="$CONFIG_SHELL"
+       export SHELL
+       echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+          test "X$echo_testing_string" = 'X\t' &&
+          echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+          test "X$echo_testing_string" = "X$echo_test_string"; then
+       echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      else
+       # maybe with a smaller string...
+       prev=:
+
+       for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+         if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+         then
+           break
+         fi
+         prev="$cmd"
+       done
+
+       if test "$prev" != 'sed 50q "[$]0"'; then
+         echo_test_string=`eval $prev`
+         export echo_test_string
+         exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+       else
+         # Oops.  We lost completely, so just stick with echo.
+         echo=echo
+       fi
+      fi
+    fi
+  fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+  ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $echo "X$_lt_compiler_boilerplate" | $Xsed >conftest.exp
+     $SED '/^$/d' conftest.err >conftest.er2
+     if test ! -s conftest.err || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$5], , :, [$5])
+else
+    ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $echo "X$_lt_linker_boilerplate" | $Xsed > conftest.exp
+       $SED '/^$/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$4], , :, [$4])
+else
+    ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536 # usable default for *BSD
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    # 
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  *)
+    # If test is not a shell built-in, we'll probably end up computing a
+    # maximum length that is only half of the actual maximum length, but
+    # we can't tell.
+    SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+    while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+              = "XX$teststring") >/dev/null 2>&1 &&
+           new_result=`expr "X$teststring" : ".*" 2>&1` &&
+           lt_cv_sys_max_cmd_len=$new_result &&
+           test $i != 17 # 1/2 MB should be enough
+    do
+      i=`expr $i + 1`
+      teststring=$teststring$teststring
+    done
+    teststring=
+    # Add a significant safety factor because C++ compilers can tack on massive
+    # amounts of additional arguments before passing them to the linker.
+    # It appears as though 1/2 is a usable value.
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# --------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}]
+EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_unknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# -------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+   ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+         [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+       [AC_CHECK_FUNC([dlopen],
+             [lt_cv_dlopen="dlopen"],
+         [AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+           [AC_CHECK_LIB([svld], [dlopen],
+                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+             [AC_CHECK_LIB([dld], [dld_link],
+                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+             ])
+           ])
+         ])
+       ])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+         lt_cv_dlopen_self, [dnl
+         _LT_AC_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+         lt_cv_dlopen_self_static, [dnl
+         _LT_AC_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $echo "X$_lt_compiler_boilerplate" | $Xsed > out/conftest.exp
+     $SED '/^$/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.err || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         AC_MSG_RESULT([yes])
+       else
+  AC_MSG_RESULT([no])
+fi
+       ;;
+   *)
+  AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+       :
+      else
+       can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+    if AC_TRY_EVAL(ac_compile); then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_ARG_WITH([tags],
+    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+        [include additional configurations @<:@automatic@:>@])],
+    [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    AC_MSG_WARN([output file `$ofile' does not exist])
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+    else
+      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+    fi
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+    "") ;;
+    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+       ;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      AC_MSG_ERROR([tag name \"$tagname\" already exists])
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+       if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+           ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+           (test "X$CXX" != "Xg++"))) ; then
+         AC_LIBTOOL_LANG_CXX_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      F77)
+       if test -n "$F77" && test "X$F77" != "Xno"; then
+         AC_LIBTOOL_LANG_F77_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      GCJ)
+       if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+         AC_LIBTOOL_LANG_GCJ_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      RC)
+       AC_LIBTOOL_LANG_RC_CONFIG
+       ;;
+
+      *)
+       AC_MSG_ERROR([Unsupported tag name: $tagname])
+       ;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+  fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 dll's
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+       [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+#- set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+       [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="ifelse([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$CC -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | kfreebsd*-gnu | dragonfly*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case "$host_cpu" in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sco3.2v5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+    if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      # Tru64's nm complains that /dev/null is an invalid object file
+      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+      */dev/null* | *'Invalid file or object type'*)
+       lt_cv_path_NM="$tmp_nm -B"
+       break
+        ;;
+      *)
+       case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+       */dev/null*)
+         lt_cv_path_NM="$tmp_nm -p"
+         break
+         ;;
+       *)
+         lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+         continue # so that we can try to find one that supports BSD flags
+         ;;
+       esac
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments.  Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+# DIRECTORY is not provided, it is assumed to be `libltdl'.  LIBLTDL will
+# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with
+# '${top_srcdir}/' (note the single quotes!).  If your package is not
+# flat and you're not using automake, define top_builddir and
+# top_srcdir appropriately in the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case $enable_ltdl_convenience in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments.  Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+# DIRECTORY is not provided and an installed libltdl is not found, it is
+# assumed to be `libltdl'.  LIBLTDL will be prefixed with '${top_builddir}/'
+# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single
+# quotes!).  If your package is not flat and you're not using automake,
+# define top_builddir and top_srcdir appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, lt_dlinit,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AC_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    LTDLINCL=
+  fi
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+# _LT_AC_PROG_CXXCPP
+# ---------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+        [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+          [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# --------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+#
+# Check for any special shared library compilation flags.
+#
+_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
+if test "$GCC" = no; then
+  case $host_os in
+  sco3.2v5*)
+    _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
+    ;;
+  esac
+fi
+if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
+  AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
+  if echo "$old_CC $old_CFLAGS " | grep "[[    ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[        ]]" >/dev/null; then :
+  else
+    AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
+    _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
+  fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
+  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+  $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
+  [],
+  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+# Report which librarie types wil actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+    ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+  AC_PROG_LD
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+       grep 'no-whole-archive' > /dev/null; then
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  aix4* | aix5*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
+      no_entry_flag=""
+    else
+      aix_use_runtimelinking=no
+
+      # Test if we are trying to use run time linking or normal
+      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+      # need to do runtime linking.
+      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+       for ld_flag in $LDFLAGS; do
+         case $ld_flag in
+         *-brtl*)
+           aix_use_runtimelinking=yes
+           break
+           ;;
+         esac
+       done
+      esac
+
+      exp_sym_flag='-bexport'
+      no_entry_flag='-bnoentry'
+    fi
+
+    # When large executables or shared objects are built, AIX ld can
+    # have problems creating the table of contents.  If linking a library
+    # or program results in "error TOC overflow" add -mminimal-toc to
+    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+    _LT_AC_TAGVAR(archive_cmds, $1)=''
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes; then
+      case $host_os in aix4.[[012]]|aix4.[[012]].*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
+       collect2name=`${CC} -print-prog-name=collect2`
+       if test -f "$collect2name" && \
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
+       then
+         # We have reworked collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+       else
+         # We have old collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+       fi
+      esac
+      shared_flag='-shared'
+      if test "$aix_use_runtimelinking" = yes; then
+       shared_flag="$shared_flag "'${wl}-G'
+      fi
+    else
+      # not using gcc
+      if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+       shared_flag='-G'
+      else
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag='${wl}-G'
+       else
+         shared_flag='${wl}-bM:SRE'
+       fi
+      fi
+    fi
+
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+    if test "$aix_use_runtimelinking" = yes; then
+      # Warning - without using the other runtime loading flags (-brtl),
+      # -berok will link without error, but may produce a broken library.
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      _LT_AC_SYS_LIBPATH_AIX
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
+      if test "$host_cpu" = ia64; then
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+      else
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+       # Warning - without using the other run time loading flags,
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+       # -bexpall does not export symbols beginning with underscore (_)
+       _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+       # Exported symbols can be pulled into shared objects from archives
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+       # This is similar to how AIX traditionally builds it's shared libraries.
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+      fi
+    fi
+    ;;
+  chorus*)
+    case $cc_basename in
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+
+
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+    # as there is no search path for DLLs.
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+       cp $export_symbols $output_objdir/$soname.def;
+      else
+       echo EXPORTS > $output_objdir/$soname.def;
+       cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+  ;;
+      darwin* | rhapsody*)
+        case "$host_os" in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+        esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes ; then
+      lt_int_apple_cc_single_mod=no
+      output_verbose_link_cmd='echo'
+      if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+       lt_int_apple_cc_single_mod=yes
+      fi
+      if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      else
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+        fi
+        _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+          if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          else
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          fi
+            _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+      fi
+        ;;
+
+  dgux*)
+    case $cc_basename in
+      ec++*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      ghcx*)
+       # Green Hills C++ Compiler
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  freebsd[[12]]*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  freebsd-elf*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  freebsd* | kfreebsd*-gnu | dragonfly*)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+    ;;
+  gnu*)
+    ;;
+  hpux9*)
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                               # but as the default
+                               # location of the library.
+
+    case $cc_basename in
+    CC*)
+      # FIXME: insert proper C++ library support
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    aCC*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      case "$host_cpu" in
+      hppa*64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+        ;;
+      ia64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        ;;
+      *)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        ;;
+      esac
+    fi
+    case "$host_cpu" in
+    hppa*64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+    ia64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                             # but as the default
+                                             # location of the library.
+      ;;
+    *)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                             # but as the default
+                                             # location of the library.
+      ;;
+    esac
+
+    case $cc_basename in
+      CC*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      aCC*)
+       case "$host_cpu" in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       esac
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test $with_gnu_ld = no; then
+           case "$host_cpu" in
+           ia64*|hppa*64*)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+             ;;
+           *)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           esac
+         fi
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  irix5* | irix6*)
+    case $cc_basename in
+      CC*)
+       # SGI C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       # Archives containing C++ object files must be created using
+       # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test "$with_gnu_ld" = no; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+         else
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+         fi
+       fi
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+       ;;
+    esac
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    ;;
+  linux*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+       ;;
+      icpc*)
+       # Intel C++
+       with_gnu_ld=yes
+       # version 8.0 and above of icpc choke on multiply defined symbols
+       # if we add $predep_objects and $postdep_objects, however 7.1 and
+       # earlier do not add the objects themselves.
+       case `$CC -V 2>&1` in
+       *"Version 7."*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       *)  # Version 8.0 or newer
+         tmp_idyn=
+         case $host_cpu in
+           ia64*) tmp_idyn=' -i_dynamic';;
+         esac
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+       ;;
+      pgCC*)
+        # Portland Group C++ compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+        ;;
+      cxx*)
+       # Compaq C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+       runpath_var=LD_RUN_PATH
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+    esac
+    ;;
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  m88k*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  mvs*)
+    case $cc_basename in
+      cxx*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+    ;;
+  openbsd2*)
+    # C++ shared libraries are fairly broken
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  openbsd*)
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    fi
+    output_verbose_link_cmd='echo'
+    ;;
+  osf3*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Archives containing C++ object files must be created using
+       # the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+         echo "-hidden">> $lib.exp~
+         $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+         $rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  sco*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    case $cc_basename in
+      CC*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.x
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      lcc*)
+       # Lucid
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  solaris*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.2, 5.x and Centerline C++
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+       $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       case $host_os in
+         solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+         *)
+           # The C++ compiler is used as linker so we must use $wl
+           # flag to pass the commands to the underlying system
+           # linker. We must also pass each convience library through
+           # to the system linker between allextract/defaultextract.
+           # The C++ compiler will combine linker options so we
+           # cannot just pass the convience library names through
+           # without $wl.
+           # Supported since Solaris 2.6 (maybe 2.5.1?)
+           _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
+           ;;
+       esac
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+       # Archives containing C++ object files must be created using
+       # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+       ;;
+      gcx*)
+       # Green Hills C++ Compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+       # The C++ compiler must be used to create the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+       ;;
+      *)
+       # GNU C++ compiler with Solaris linker
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+         if $CC --version | grep -v '^2\.7' > /dev/null; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+         else
+           # g++ 2.7 appears to require `-G' NOT `-shared' on this
+           # platform.
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+         fi
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+       fi
+       ;;
+    esac
+    ;;
+  sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC*)
+       # NonStop-UX NCC 3.20
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+         || test $p = "-R"; then
+        prev=$p
+        continue
+       else
+        prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        case $p in
+        -L* | -R*)
+          # Internal compiler library paths should come after those
+          # provided the user.  The postdeps already come after the
+          # user supplied libs so there is no need to process them.
+          if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+          else
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+          fi
+          ;;
+        # The "-l" case would never come before the object being
+        # linked, so don't bother handling this case.
+        esac
+       else
+        if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+          _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+        else
+          _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+        fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+        pre_test_object_deps_done=yes
+        continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+          _LT_AC_TAGVAR(predep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+        fi
+       else
+        if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+          _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+        fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="      program t\n      end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+  ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars.  Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    _LT_AC_TAGVAR(compiler, $1) \
+    _LT_AC_TAGVAR(CC, $1) \
+    _LT_AC_TAGVAR(LD, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+    _LT_AC_TAGVAR(predep_objects, $1) \
+    _LT_AC_TAGVAR(postdep_objects, $1) \
+    _LT_AC_TAGVAR(predeps, $1) \
+    _LT_AC_TAGVAR(postdeps, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+    _LT_AC_TAGVAR(archive_cmds, $1) \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+    _LT_AC_TAGVAR(module_cmds, $1) \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+    _LT_AC_TAGVAR(include_expsyms, $1); do
+
+    case $var in
+    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(module_cmds, $1) | \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\[$]0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+    ;;
+  esac
+
+ifelse([$1], [],
+  [cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  AC_MSG_NOTICE([creating $ofile])],
+  [cfgfile="$ofile"])
+
+  cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e 1s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+])
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+linux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDGIRSTW]]'
+    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris* | sysv5*)
+  symcode='[[BDRT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[     ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+       if grep ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+         cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+         cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_save_LIBS="$LIBS"
+         lt_save_CFLAGS="$CFLAGS"
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS="$lt_save_LIBS"
+         CFLAGS="$lt_save_CFLAGS"
+       else
+         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -f conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix4* | aix5*)
+       # All AIX code is PIC.
+       if test "$host_cpu" = ia64; then
+         # AIX 5 now supports IA64 processor
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       else
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+       fi
+       ;;
+      chorus*)
+       case $cc_basename in
+       cxch68*)
+         # Green Hills C++ Compiler
+         # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+         ;;
+       esac
+       ;;
+       darwin*)
+         # PIC is the default on this platform
+         # Common symbols not allowed in MH_DYLIB files
+         case $cc_basename in
+           xlc*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           ;;
+         esac
+       ;;
+      dgux*)
+       case $cc_basename in
+         ec++*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         ghcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      freebsd* | kfreebsd*-gnu | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+      hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+           if test "$host_cpu" != ia64; then
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+           case "$host_cpu" in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+           *)
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+             ;;
+           esac
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           # CC pic flag -KPIC is the default.
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      linux*)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         icpc* | ecpc*)
+           # Intel C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         pgCC*)
+           # Portland Group C++ compiler.
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         cxx*)
+           # Compaq C++
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      lynxos*)
+       ;;
+      m88k*)
+       ;;
+      mvs*)
+       case $cc_basename in
+         cxx*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      netbsd*)
+       ;;
+      osf3* | osf4* | osf5*)
+       case $cc_basename in
+         KCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           ;;
+         RCC*)
+           # Rational C++ 2.4.1
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         cxx*)
+           # Digital/Compaq C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      psos*)
+       ;;
+      sco*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      solaris*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+           ;;
+         gcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sunos4*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.x
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         lcc*)
+           # Lucid
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      tandem*)
+       case $cc_basename in
+         NCC*)
+           # NonStop-UX NCC 3.20
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      unixware*)
+       ;;
+      vxworks*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+      darwin*)
+        # PIC is the default on this platform
+        # Common symbols not allowed in MH_DYLIB files
+       case $cc_basename in
+         xlc*)
+         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+       esac
+       ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    linux*)
+      case $cc_basename in
+      icc* | ecc*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      pgcc* | pgf77* | pgf90*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      ccc*)
+        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    unicos*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix4* | aix5*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+],[
+  runpath_var=
+  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_AC_TAGVAR(archive_cmds, $1)=
+  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+  _LT_AC_TAGVAR(module_cmds, $1)=
+  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_AC_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+  # Just being paranoid about ensuring that cc_basename is set.
+  _LT_CC_BASENAME([$compiler])
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+    
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>/dev/null` in
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+    
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    linux*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       tmp_addflag=
+       case $cc_basename,$host_cpu in
+       pgcc*)                          # Portland Group C compiler
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+         ;;
+       pgf77* | pgf90* )                       # Portland Group f77 and f90 compilers
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+         tmp_addflag=' -fpic -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)                # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+       if test $supports_anon_versioning = yes; then
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+  $echo "local: *; };" >> $output_objdir/$libname.ver~
+         $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+       fi
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       else
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+       esac
+
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_AC_TAGVAR(archive_cmds, $1)=''
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" && \
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         else
+         # We have old collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+       if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+       fi
+       fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+       if test "$host_cpu" = ia64; then
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an empty executable.
+        _LT_AC_SYS_LIBPATH_AIX
+        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+         # -bexpall does not export symbols beginning with underscore (_)
+         _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+         # Exported symbols can be pulled into shared objects from archives
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+         # This is similar to how AIX traditionally builds it's shared libraries.
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      # see comment about different semantics on the GNU ld section
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    bsdi[[45]]*)
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+      case "$host_os" in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+      esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    if test "$GCC" = yes ; then
+       output_verbose_link_cmd='echo'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+    fi
+      ;;
+
+    dgux*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu | dragonfly*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+       case "$host_cpu" in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case "$host_cpu" in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       case "$host_cpu" in
+       hppa*64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+         ;;
+       ia64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       *)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    openbsd*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      else
+       case $host_os in
+        openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+          ;;
+        *)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+          ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+       $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+         $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+       wlarc=''
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+       $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+       # The compiler driver will combine linker options so we
+       # cannot just pass the convience library names through
+       # without $wl, iff we do not link with $LD.
+       # Luckily, gcc supports the same syntax we need for Sun Studio.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       case $wlarc in
+       '')
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+       *)
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+       esac ;;
+      esac
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+        ;;
+       motorola)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[[78]]* | unixware7*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv5*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+        then
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
+  ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+  AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_MSG_RESULT([$SED])
+])
+
+# Figure out how to run the assembler.             -*- Autoconf -*-
+
+# serial 2
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# AM_PROG_AS
+# ----------
+AC_DEFUN([AM_PROG_AS],
+[# By default we simply use the C compiler to build assembly code.
+AC_REQUIRE([AC_PROG_CC])
+: ${CCAS='$(CC)'}
+# Set ASFLAGS if not already set.
+: ${CCASFLAGS='$(CFLAGS)'}
+AC_SUBST(CCAS)
+AC_SUBST(CCASFLAGS)])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*-
+
+# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# 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, 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.
+
+AC_PREREQ([2.52])
+
+# serial 6
+
+# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# CFLAGS and library paths for XMMS
+# written 15 December 1999 by Ben Gertzfield <che@debian.org>
+
+dnl Usage:
+dnl AM_PATH_XMMS([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl
+dnl Example:
+dnl AM_PATH_XMMS(0.9.5.1, , AC_MSG_ERROR([*** XMMS >= 0.9.5.1 not installed - please install first ***]))
+dnl
+dnl Defines XMMS_CFLAGS, XMMS_LIBS, XMMS_DATA_DIR, XMMS_PLUGIN_DIR, 
+dnl XMMS_VISUALIZATION_PLUGIN_DIR, XMMS_INPUT_PLUGIN_DIR, 
+dnl XMMS_OUTPUT_PLUGIN_DIR, XMMS_GENERAL_PLUGIN_DIR, XMMS_EFFECT_PLUGIN_DIR,
+dnl and XMMS_VERSION for your plugin pleasure.
+dnl
+
+dnl XMMS_TEST_VERSION(AVAILABLE-VERSION, NEEDED-VERSION [, ACTION-IF-OKAY [, ACTION-IF-NOT-OKAY]])
+AC_DEFUN([XMMS_TEST_VERSION], [
+
+# Determine which version number is greater. Prints 2 to stdout if     
+# the second number is greater, 1 if the first number is greater,      
+# 0 if the numbers are equal.                                          
+                                                                       
+# Written 15 December 1999 by Ben Gertzfield <che@debian.org>          
+# Revised 15 December 1999 by Jim Monty <monty@primenet.com>           
+                                                                       
+    AC_PROG_AWK
+    xmms_got_version=[` $AWK '                                         \
+BEGIN {                                                                        \
+    print vercmp(ARGV[1], ARGV[2]);                                    \
+}                                                                      \
+                                                                       \
+function vercmp(ver1, ver2,    ver1arr, ver2arr,                       \
+                               ver1len, ver2len,                       \
+                               ver1int, ver2int, len, i, p) {          \
+                                                                       \
+    ver1len = split(ver1, ver1arr, /\./);                              \
+    ver2len = split(ver2, ver2arr, /\./);                              \
+                                                                       \
+    len = ver1len > ver2len ? ver1len : ver2len;                       \
+                                                                       \
+    for (i = 1; i <= len; i++) {                                       \
+        p = 1000 ^ (len - i);                                          \
+        ver1int += ver1arr[i] * p;                                     \
+        ver2int += ver2arr[i] * p;                                     \
+    }                                                                  \
+                                                                       \
+    if (ver1int < ver2int)                                             \
+        return 2;                                                      \
+    else if (ver1int > ver2int)                                                \
+        return 1;                                                      \
+    else                                                               \
+        return 0;                                                      \
+}' $1 $2`]                                                             
+
+    if test $xmms_got_version -eq 2; then      # failure
+       ifelse([$4], , :, $4)                   
+    else                                       # success!
+       ifelse([$3], , :, $3)
+    fi
+])
+
+AC_DEFUN([AM_PATH_XMMS],
+[
+AC_ARG_WITH(xmms-prefix,[  --with-xmms-prefix=PFX  Prefix where XMMS is installed (optional)],
+       xmms_config_prefix="$withval", xmms_config_prefix="")
+AC_ARG_WITH(xmms-exec-prefix,[  --with-xmms-exec-prefix=PFX Exec prefix where XMMS is installed (optional)],
+       xmms_config_exec_prefix="$withval", xmms_config_exec_prefix="")
+
+if test x$xmms_config_exec_prefix != x; then
+    xmms_config_args="$xmms_config_args --exec-prefix=$xmms_config_exec_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+       XMMS_CONFIG=$xmms_config_exec_prefix/bin/xmms-config
+    fi
+fi
+
+if test x$xmms_config_prefix != x; then
+    xmms_config_args="$xmms_config_args --prefix=$xmms_config_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+       XMMS_CONFIG=$xmms_config_prefix/bin/xmms-config
+    fi
+fi
+
+AC_PATH_PROG(XMMS_CONFIG, xmms-config, no)
+min_xmms_version=ifelse([$1], ,0.9.5.1, $1)
+
+if test "$XMMS_CONFIG" = "no"; then
+    no_xmms=yes
+else
+    XMMS_CFLAGS=`$XMMS_CONFIG $xmms_config_args --cflags`
+    XMMS_LIBS=`$XMMS_CONFIG $xmms_config_args --libs`
+    XMMS_VERSION=`$XMMS_CONFIG $xmms_config_args --version`
+    XMMS_DATA_DIR=`$XMMS_CONFIG $xmms_config_args --data-dir`
+    XMMS_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --plugin-dir`
+    XMMS_VISUALIZATION_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args \
+                                       --visualization-plugin-dir`
+    XMMS_INPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --input-plugin-dir`
+    XMMS_OUTPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --output-plugin-dir`
+    XMMS_EFFECT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --effect-plugin-dir`
+    XMMS_GENERAL_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --general-plugin-dir`
+
+    XMMS_TEST_VERSION($XMMS_VERSION, $min_xmms_version, ,no_xmms=version)
+fi
+
+AC_MSG_CHECKING(for XMMS - version >= $min_xmms_version)
+
+if test "x$no_xmms" = x; then
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+else
+    AC_MSG_RESULT(no)
+
+    if test "$XMMS_CONFIG" = "no" ; then
+       echo "*** The xmms-config script installed by XMMS could not be found."
+       echo "*** If XMMS was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the XMMS_CONFIG environment variable to the"
+       echo "*** full path to xmms-config."
+    else
+       if test "$no_xmms" = "version"; then
+           echo "*** An old version of XMMS, $XMMS_VERSION, was found."
+           echo "*** You need a version of XMMS newer than $min_xmms_version."
+           echo "*** The latest version of XMMS is always available from"
+           echo "*** http://www.xmms.org/"
+           echo "***"
+
+            echo "*** If you have already installed a sufficiently new version, this error"
+            echo "*** probably means that the wrong copy of the xmms-config shell script is"
+            echo "*** being found. The easiest way to fix this is to remove the old version"
+            echo "*** of XMMS, but you can also set the XMMS_CONFIG environment to point to the"
+            echo "*** correct copy of xmms-config. (In this case, you will have to"
+            echo "*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf"
+            echo "*** so that the correct libraries are found at run-time)"
+       fi
+    fi
+    XMMS_CFLAGS=""
+    XMMS_LIBS=""
+    ifelse([$3], , :, [$3])
+fi
+AC_SUBST(XMMS_CFLAGS)
+AC_SUBST(XMMS_LIBS)
+AC_SUBST(XMMS_VERSION)
+AC_SUBST(XMMS_DATA_DIR)
+AC_SUBST(XMMS_PLUGIN_DIR)
+AC_SUBST(XMMS_VISUALIZATION_PLUGIN_DIR)
+AC_SUBST(XMMS_INPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_OUTPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_GENERAL_PLUGIN_DIR)
+AC_SUBST(XMMS_EFFECT_PLUGIN_DIR)
+])
+
+# Configure paths for libogg
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_OGG],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ogg,[  --with-ogg=PFX   Prefix where libogg is installed (optional)], ogg_prefix="$withval", ogg_prefix="")
+AC_ARG_WITH(ogg-libraries,[  --with-ogg-libraries=DIR   Directory where libogg library is installed (optional)], ogg_libraries="$withval", ogg_libraries="")
+AC_ARG_WITH(ogg-includes,[  --with-ogg-includes=DIR   Directory where libogg header files are installed (optional)], ogg_includes="$withval", ogg_includes="")
+AC_ARG_ENABLE(oggtest, [  --disable-oggtest       Do not try to compile and run a test Ogg program],, enable_oggtest=yes)
+
+  if test "x$ogg_libraries" != "x" ; then
+    OGG_LIBS="-L$ogg_libraries"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_LIBS="-L$ogg_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    OGG_LIBS="-L$prefix/lib"
+  fi
+
+  OGG_LIBS="$OGG_LIBS -logg"
+
+  if test "x$ogg_includes" != "x" ; then
+    OGG_CFLAGS="-I$ogg_includes"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_CFLAGS="-I$ogg_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    OGG_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Ogg)
+  no_ogg=""
+
+
+  if test "x$enable_oggtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Ogg is sufficiently new.
+dnl
+      rm -f conf.oggtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+int main ()
+{
+  system("touch conf.oggtest");
+  return 0;
+}
+
+],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ogg" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.oggtest ; then
+       :
+     else
+       echo "*** Could not run Ogg test program, checking why..."
+       CFLAGS="$CFLAGS $OGG_CFLAGS"
+       LIBS="$LIBS $OGG_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <ogg/ogg.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Ogg or finding the wrong"
+       echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means Ogg was incorrectly installed"
+       echo "*** or that you have moved Ogg since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     OGG_CFLAGS=""
+     OGG_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(OGG_CFLAGS)
+  AC_SUBST(OGG_LIBS)
+  rm -f conf.oggtest
+])
+
+# iconv.m4 serial AM4 (gettext-0.11.3)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+  dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed libiconv and not disabled its use
+  dnl via --without-libiconv-prefix, he wants to use it. The first
+  dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+  am_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+  AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+      [iconv_t cd = iconv_open("","");
+       iconv(cd,NULL,NULL,NULL,NULL);
+       iconv_close(cd);],
+      am_cv_func_iconv=yes)
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS $LIBICONV"
+      AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+        [iconv_t cd = iconv_open("","");
+         iconv(cd,NULL,NULL,NULL,NULL);
+         iconv_close(cd);],
+        am_cv_lib_iconv=yes
+        am_cv_func_iconv=yes)
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+  fi
+  if test "$am_cv_lib_iconv" = yes; then
+    AC_MSG_CHECKING([how to link with libiconv])
+    AC_MSG_RESULT([$LIBICONV])
+  else
+    dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+    dnl either.
+    CPPFLAGS="$am_save_CPPFLAGS"
+    LIBICONV=
+    LTLIBICONV=
+  fi
+  AC_SUBST(LIBICONV)
+  AC_SUBST(LTLIBICONV)
+])
+
+AC_DEFUN([AM_ICONV],
+[
+  AM_ICONV_LINK
+  if test "$am_cv_func_iconv" = yes; then
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL(am_cv_proto_iconv, [
+      AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([$]{ac_t:-
+         }[$]am_cv_proto_iconv)
+    AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+      [Define as const if the declaration of iconv() needs const.])
+  fi
+])
+
+# lib-prefix.m4 serial 4 (gettext-0.14.2)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+  AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib-prefix],
+[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+])
+  if test $use_additional = yes; then
+    dnl Potentially add $additional_includedir to $CPPFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/include,
+    dnl   2. if it's already present in $CPPFLAGS,
+    dnl   3. if it's /usr/local/include and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_includedir" != "X/usr/include"; then
+      haveit=
+      for x in $CPPFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-I$additional_includedir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_includedir" = "X/usr/local/include"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_includedir"; then
+            dnl Really add $additional_includedir to $CPPFLAGS.
+            CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+          fi
+        fi
+      fi
+    fi
+    dnl Potentially add $additional_libdir to $LDFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/lib,
+    dnl   2. if it's already present in $LDFLAGS,
+    dnl   3. if it's /usr/local/lib and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_libdir" != "X/usr/lib"; then
+      haveit=
+      for x in $LDFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-L$additional_libdir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_libdir" = "X/usr/local/lib"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux*) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_libdir"; then
+            dnl Really add $additional_libdir to $LDFLAGS.
+            LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+          fi
+        fi
+      fi
+    fi
+  fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+  dnl Unfortunately, prefix and exec_prefix get only finally determined
+  dnl at the end of configure.
+  if test "X$prefix" = "XNONE"; then
+    acl_final_prefix="$ac_default_prefix"
+  else
+    acl_final_prefix="$prefix"
+  fi
+  if test "X$exec_prefix" = "XNONE"; then
+    acl_final_exec_prefix='${prefix}'
+  else
+    acl_final_exec_prefix="$exec_prefix"
+  fi
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  $1
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+])
+
+# lib-link.m4 serial 6 (gettext-0.14.3)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ(2.50)
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+    AC_LIB_LINKFLAGS_BODY([$1], [$2])
+    ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+    ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+    ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+  ])
+  LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+  LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+  INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+  dnl results of this search when this library appears as a dependency.
+  HAVE_LIB[]NAME=yes
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+  dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+  dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed lib[]Name and not disabled its use
+  dnl via --without-lib[]Name-prefix, he wants to use it.
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+  AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIB[]NAME"
+    AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+    LIBS="$ac_save_LIBS"
+  ])
+  if test "$ac_cv_lib[]Name" = yes; then
+    HAVE_LIB[]NAME=yes
+    AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+    AC_MSG_CHECKING([how to link with lib[]$1])
+    AC_MSG_RESULT([$LIB[]NAME])
+  else
+    HAVE_LIB[]NAME=no
+    dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+    dnl $INC[]NAME either.
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIB[]NAME=
+    LTLIB[]NAME=
+  fi
+  AC_SUBST([HAVE_LIB]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
+  AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
+  AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
+  AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+  AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+    CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+    ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+    . ./conftest.sh
+    rm -f ./conftest.sh
+    acl_cv_rpath=done
+  ])
+  wl="$acl_cv_wl"
+  libext="$acl_cv_libext"
+  shlibext="$acl_cv_shlibext"
+  hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+  hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+  hardcode_direct="$acl_cv_hardcode_direct"
+  hardcode_minus_L="$acl_cv_hardcode_minus_L"
+  dnl Determine whether the user wants rpath handling at all.
+  AC_ARG_ENABLE(rpath,
+    [  --disable-rpath         do not hardcode runtime library paths],
+    :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib$1-prefix],
+[  --with-lib$1-prefix[=DIR]  search for lib$1 in DIR/include and DIR/lib
+  --without-lib$1-prefix     don't search for lib$1 in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+])
+  dnl Search the library and its dependencies in $additional_libdir and
+  dnl $LDFLAGS. Using breadth-first-seach.
+  LIB[]NAME=
+  LTLIB[]NAME=
+  INC[]NAME=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='$1 $2'
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+        dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+        dnl or AC_LIB_HAVE_LINKFLAGS call.
+        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+          else
+            dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+            dnl that this library doesn't exist. So just drop it.
+            :
+          fi
+        else
+          dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+          dnl and the already constructed $LIBNAME/$LTLIBNAME.
+          found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            else
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIB[]NAME; do
+              AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  else
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+            dnl Found the library.
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+              dnl Linking with a shared library. We attempt to hardcode its
+              dnl directory into the executable's runpath, unless it's the
+              dnl standard /usr/lib.
+              if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+                dnl No hardcoding is needed.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+              else
+                dnl Use an explicit option to hardcode DIR into the resulting
+                dnl binary.
+                dnl Potentially add DIR to ltrpathdirs.
+                dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                dnl The hardcoding into $LIBNAME is system dependent.
+                if test "$hardcode_direct" = yes; then
+                  dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+                  dnl resulting binary.
+                  LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                    dnl Use an explicit option to hardcode DIR into the resulting
+                    dnl binary.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    dnl Potentially add DIR to rpathdirs.
+                    dnl The rpathdirs will be appended to $LIBNAME at the end.
+                    haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                    dnl Rely on "-L$found_dir".
+                    dnl But don't add it if it's already contained in the LDFLAGS
+                    dnl or the already constructed $LIBNAME
+                    haveit=
+                    for x in $LDFLAGS $LIB[]NAME; do
+                      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    else
+                      dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+                      dnl here, because this doesn't fit in flags passed to the
+                      dnl compiler. So give up. No hardcoding. This affects only
+                      dnl very old systems.
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                dnl Linking with a static library.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+              else
+                dnl We shouldn't come here, but anyway it's good to have a
+                dnl fallback.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+              fi
+            fi
+            dnl Assume the include files are nearby.
+            additional_includedir=
+            case "$found_dir" in
+              */lib | */lib/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+              dnl Potentially add $additional_includedir to $INCNAME.
+              dnl But don't add it
+              dnl   1. if it's the standard /usr/include,
+              dnl   2. if it's /usr/local/include and we are using GCC on Linux,
+              dnl   3. if it's already present in $CPPFLAGS or the already
+              dnl      constructed $INCNAME,
+              dnl   4. if it doesn't exist as a directory.
+              if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INC[]NAME; do
+                    AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                      dnl Really add $additional_includedir to $INCNAME.
+                      INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+            dnl Look for dependencies.
+            if test -n "$found_la"; then
+              dnl Read the .la file. It defines the variables
+              dnl dlname, library_names, old_library, dependency_libs, current,
+              dnl age, revision, installed, dlopen, dlpreopen, libdir.
+              save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+              dnl We use only dependency_libs.
+              for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dnl But don't add it
+                    dnl   1. if it's the standard /usr/lib,
+                    dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
+                    dnl   3. if it's already present in $LDFLAGS or the already
+                    dnl      constructed $LIBNAME,
+                    dnl   4. if it doesn't exist as a directory.
+                    if test "X$additional_libdir" != "X/usr/lib"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/lib"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                      dnl Potentially add DIR to rpathdirs.
+                      dnl The rpathdirs will be appended to $LIBNAME at the end.
+                      haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                      dnl Potentially add DIR to ltrpathdirs.
+                      dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                      haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                    dnl Handle this in the next round.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                    dnl Handle this in the next round. Throw away the .la's
+                    dnl directory; it is already contained in a preceding -L
+                    dnl option.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                    dnl Most likely an immediate library name.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+                    LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+            dnl Didn't find the library; assume it is in the system directories
+            dnl known to the linker and runtime loader. (All the system
+            dnl directories known to the linker should also be known to the
+            dnl runtime loader, otherwise the system is severely misconfigured.)
+            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+      dnl Weird platform: only the last -rpath option counts, the user must
+      dnl pass all path elements in one option. We can arrange that for a
+      dnl single library, but not when more than one $LIBNAMEs are used.
+      alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+      dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+      acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+    else
+      dnl The -rpath options are cumulative.
+      for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+    dnl When using libtool, the option that works for both libraries and
+    dnl executables is -R. The -R options are cumulative.
+    for found_dir in $ltrpathdirs; do
+      LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+    done
+  fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+  for element in [$2]; do
+    haveit=
+    for x in $[$1]; do
+      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      [$1]="${[$1]}${[$1]:+ }$element"
+    fi
+  done
+])
+
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes ;;
+*)
+  acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]* | [A-Za-z]:[\\/]*)]
+      [re_direlt='/[^/][^/]*/\.\./']
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(acl_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      acl_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break ;;
+      *)
+       test "$with_gnu_ld" != yes && break ;;
+      esac
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
+
+# codeset.m4 serial AM1 (gettext-0.10.40)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+  AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
+    [AC_TRY_LINK([#include <langinfo.h>],
+      [char* cs = nl_langinfo(CODESET);],
+      am_cv_langinfo_codeset=yes,
+      am_cv_langinfo_codeset=no)
+    ])
+  if test $am_cv_langinfo_codeset = yes; then
+    AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
+      [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+  fi
+])
+
diff --git a/all.dsp b/all.dsp
new file mode 100644 (file)
index 0000000..9fc561c
--- /dev/null
+++ b/all.dsp
@@ -0,0 +1,67 @@
+# Microsoft Developer Studio Project File - Name="all" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a\r
+\r
+CFG=all - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all.mak" CFG="all - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "all - Win32 Release" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE "all - Win32 Debug" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "all"\r
+# PROP Scc_LocalPath "."\r
+MTL=midl.exe\r
+\r
+!IF  "$(CFG)" == "all - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "obj\release"\r
+# PROP Intermediate_Dir "obj\release"\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "all - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "obj\debug"\r
+# PROP Intermediate_Dir "obj\debug"\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "all - Win32 Release"\r
+# Name "all - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\README\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/all_dynamic.dsp b/all_dynamic.dsp
new file mode 100644 (file)
index 0000000..4368bbf
--- /dev/null
@@ -0,0 +1,67 @@
+# Microsoft Developer Studio Project File - Name="all_dynamic" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a\r
+\r
+CFG=all_dynamic - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all_dynamic.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all_dynamic.mak" CFG="all_dynamic - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "all_dynamic - Win32 Release" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE "all_dynamic - Win32 Debug" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "all"\r
+# PROP Scc_LocalPath "."\r
+MTL=midl.exe\r
+\r
+!IF  "$(CFG)" == "all_dynamic - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "obj\release"\r
+# PROP Intermediate_Dir "obj\release"\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "all_dynamic - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "obj\debug"\r
+# PROP Intermediate_Dir "obj\debug"\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "all_dynamic - Win32 Release"\r
+# Name "all_dynamic - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\README\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/all_static.dsp b/all_static.dsp
new file mode 100644 (file)
index 0000000..a56a1c9
--- /dev/null
@@ -0,0 +1,67 @@
+# Microsoft Developer Studio Project File - Name="all_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a\r
+\r
+CFG=all_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all_static.mak" CFG="all_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "all_static - Win32 Release" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE "all_static - Win32 Debug" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "all"\r
+# PROP Scc_LocalPath "."\r
+MTL=midl.exe\r
+\r
+!IF  "$(CFG)" == "all_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "obj\release"\r
+# PROP Intermediate_Dir "obj\release"\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "all_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "obj\debug"\r
+# PROP Intermediate_Dir "obj\debug"\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "all_static - Win32 Release"\r
+# Name "all_static - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\README\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..6ba76d0
--- /dev/null
@@ -0,0 +1,162 @@
+#!/bin/sh
+# Run this to set up the build system: configure, makefiles, etc.
+# (based on the version in enlightenment's cvs)
+
+# Some notes:
+#
+# You may need to specify -I /SOME_PATH/share/aclocal in ACLOCAL_FLAGS
+# if any packages FLAC relies on (autotools, libogg, libiconv) are
+# installed in non-standard places.
+#
+# If you don't have XMMS installed at all, you should comment out
+# AM_PATH_XMMS in configure.in.
+#
+# FLAC uses iconv but not gettext.  iconv requires config.rpath which
+# is supplied by gettext, which is copied in by gettextize.  But we
+# can't run gettextize since we do not fulfill all it's requirements
+# (because we don't use it).  So you may have to:
+#
+#   cp /usr/share/gettext/config.rpath .
+#
+# before running autogen.sh
+#
+# If you are running on OS X and get errors related to the AM_ICONV
+# and/or AM_LANGINFO_CODESET macros, replace those 2 lines in
+# configure.in with
+#
+#   AC_DEFINE([HAVE_ICONV], [], [Whether we have libiconv available]) LIBICONV="-liconv"
+#   AC_SUBST(LIBICONV)
+#
+# See also http://lists.xiph.org/pipermail/flac-dev/2007-September/002384.html
+#
+# Also watchout, if you replace ltmain.sh, there is a bug in some
+# versions of libtool (or maybe autoconf) on some platforms where the
+# configure-generated libtool does not have $SED defined.  See also:
+#
+#   http://lists.gnu.org/archive/html/libtool/2003-11/msg00131.html
+
+package="flac"
+
+olddir=`pwd`
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+cd "$srcdir"
+DIE=0
+
+ACLOCAL_FLAGS="-I m4 $ACLOCAL_FLAGS"
+
+echo "checking for autoconf... "
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have autoconf installed to compile $package."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+        DIE=1
+}
+
+VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/"
+VERSIONMKMAJ="sed -e s/\([0-9][0-9]*\)[^0-9].*/\\1/"
+VERSIONMKMIN="sed -e s/.*[0-9][0-9]*\.//"
+
+# do we need automake?
+if test -r Makefile.am; then
+  AM_OPTIONS=`fgrep AUTOMAKE_OPTIONS Makefile.am`
+  AM_NEEDED=`echo $AM_OPTIONS | $VERSIONGREP`
+  if test x"$AM_NEEDED" = "x$AM_OPTIONS"; then
+    AM_NEEDED=""
+  fi
+  if test -z $AM_NEEDED; then
+    echo -n "checking for automake... "
+    AUTOMAKE=automake
+    ACLOCAL=aclocal
+    if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then
+      echo "yes"
+    else
+      echo "no"
+      AUTOMAKE=
+    fi
+  else
+    echo -n "checking for automake $AM_NEEDED or later... "
+    majneeded=`echo $AM_NEEDED | $VERSIONMKMAJ`
+    minneeded=`echo $AM_NEEDED | $VERSIONMKMIN`
+    for am in automake-$AM_NEEDED automake$AM_NEEDED \
+       automake automake-1.7 automake-1.8 automake-1.9 automake-1.10; do
+      ($am --version < /dev/null > /dev/null 2>&1) || continue
+      ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP`
+      maj=`echo $ver | $VERSIONMKMAJ`
+      min=`echo $ver | $VERSIONMKMIN`
+      if test $maj -eq $majneeded -a $min -ge $minneeded; then
+        AUTOMAKE=$am
+        echo $AUTOMAKE
+        break
+      fi
+    done
+    test -z $AUTOMAKE &&  echo "no"
+    echo -n "checking for aclocal $AM_NEEDED or later... "
+    for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED \
+       aclocal aclocal-1.7 aclocal-1.8 aclocal-1.9 aclocal-1.10; do
+      ($ac --version < /dev/null > /dev/null 2>&1) || continue
+      ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP`
+      maj=`echo $ver | $VERSIONMKMAJ`
+      min=`echo $ver | $VERSIONMKMIN`
+      if test $maj -eq $majneeded -a $min -ge $minneeded; then
+        ACLOCAL=$ac
+        echo $ACLOCAL
+        break
+      fi
+    done
+    test -z $ACLOCAL && echo "no"
+  fi
+  test -z $AUTOMAKE || test -z $ACLOCAL && {
+        echo
+        echo "You must have automake installed to compile $package."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+        exit 1
+  }
+fi
+
+echo -n "checking for libtool... "
+for LIBTOOLIZE in libtoolize glibtoolize nope; do
+  ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 && break
+done
+if test x$LIBTOOLIZE = xnope; then
+  echo "nope."
+  LIBTOOLIZE=libtoolize
+else
+  echo $LIBTOOLIZE
+fi
+($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
+       echo
+       echo "You must have libtool installed to compile $package."
+       echo "Download the appropriate package for your system,"
+       echo "or get the source from one of the GNU ftp sites"
+       echo "listed in http://www.gnu.org/order/ftp.html"
+       DIE=1
+}
+
+if test "$DIE" -eq 1; then
+        exit 1
+fi
+
+if test -z "$*"; then
+        echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+echo "Generating configuration files for $package, please wait...."
+
+echo "  $ACLOCAL $ACLOCAL_FLAGS"
+$ACLOCAL $ACLOCAL_FLAGS || exit 1
+echo "  $LIBTOOLIZE --automake"
+$LIBTOOLIZE --automake || exit 1
+echo "  autoheader"
+autoheader || exit 1
+echo "  $AUTOMAKE --add-missing $AUTOMAKE_FLAGS"
+$AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1
+echo "  autoconf"
+autoconf || exit 1
+
+cd $olddir
+$srcdir/configure --enable-maintainer-mode "$@" && echo
diff --git a/build/Makefile.am b/build/Makefile.am
new file mode 100644 (file)
index 0000000..7ec88fe
--- /dev/null
@@ -0,0 +1,21 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       config.mk \
+       exe.mk \
+       lib.mk
diff --git a/build/config.mk b/build/config.mk
new file mode 100644 (file)
index 0000000..477de0f
--- /dev/null
@@ -0,0 +1,52 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# debug/release selection
+#
+
+DEFAULT_BUILD = release
+
+debug    : BUILD = debug
+valgrind : BUILD = debug
+release  : BUILD = release
+
+# override LINKAGE on OS X until we figure out how to get 'cc -static' to work
+ifeq ($(DARWIN_BUILD),yes)
+LINKAGE = 
+else
+debug    : LINKAGE = -static
+valgrind : LINKAGE = -dynamic
+release  : LINKAGE = -static
+endif
+
+all default: $(DEFAULT_BUILD)
+
+#
+# GNU makefile fragment for emulating stuff normally done by configure
+#
+
+VERSION=\"1.2.1\"
+
+ifeq ($(DARWIN_BUILD),yes)
+CONFIG_CFLAGS=-DHAVE_INTTYPES_H -DHAVE_ICONV -DHAVE_LANGINFO_CODESET -DFLAC__HAS_OGG -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DFLAC__SYS_DARWIN -DWORDS_BIGENDIAN
+else
+CONFIG_CFLAGS=-DHAVE_INTTYPES_H -DHAVE_ICONV -DHAVE_LANGINFO_CODESET -DHAVE_SOCKLEN_T -DFLAC__HAS_OGG -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+
+OGG_INCLUDE_DIR=$(HOME)/local/include
+OGG_LIB_DIR=$(HOME)/local/lib
diff --git a/build/exe.mk b/build/exe.mk
new file mode 100644 (file)
index 0000000..89ce2c0
--- /dev/null
@@ -0,0 +1,97 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile fragment for building an executable
+#
+
+include $(topdir)/build/config.mk
+
+ifeq ($(DARWIN_BUILD),yes)
+CC          = cc
+CCC         = c++
+else
+CC          = gcc
+CCC         = g++
+endif
+NASM        = nasm
+LINK        = $(CC) $(LINKAGE)
+OBJPATH     = $(topdir)/obj
+BINPATH     = $(OBJPATH)/$(BUILD)/bin
+LIBPATH     = $(OBJPATH)/$(BUILD)/lib
+DEBUG_BINPATH   = $(OBJPATH)/debug/bin
+DEBUG_LIBPATH   = $(OBJPATH)/debug/lib
+RELEASE_BINPATH = $(OBJPATH)/release/bin
+RELEASE_LIBPATH = $(OBJPATH)/release/lib
+PROGRAM         = $(BINPATH)/$(PROGRAM_NAME)
+DEBUG_PROGRAM   = $(DEBUG_BINPATH)/$(PROGRAM_NAME)
+RELEASE_PROGRAM = $(RELEASE_BINPATH)/$(PROGRAM_NAME)
+
+debug   : CFLAGS = -g -O0 -DDEBUG $(CONFIG_CFLAGS) $(DEBUG_CFLAGS) -W -Wall -Wmissing-prototypes -Wstrict-prototypes -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+valgrind: CFLAGS = -g -O0 -DDEBUG $(CONFIG_CFLAGS) $(DEBUG_CFLAGS) -DFLAC__VALGRIND_TESTING -W -Wall -Wmissing-prototypes -Wstrict-prototypes -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+release : CFLAGS = -O3 -fomit-frame-pointer -funroll-loops -finline-functions -DNDEBUG $(CONFIG_CFLAGS) $(RELEASE_CFLAGS) -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Winline -DFLaC__INLINE=__inline__ -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+
+LFLAGS  = -L$(LIBPATH)
+
+DEBUG_OBJS = $(SRCS_C:%.c=%.debug.o) $(SRCS_CC:%.cc=%.debug.o) $(SRCS_CPP:%.cpp=%.debug.o) $(SRCS_NASM:%.nasm=%.debug.o)
+RELEASE_OBJS = $(SRCS_C:%.c=%.release.o) $(SRCS_CC:%.cc=%.release.o) $(SRCS_CPP:%.cpp=%.release.o) $(SRCS_NASM:%.nasm=%.release.o)
+
+debug   : $(DEBUG_PROGRAM)
+valgrind: $(DEBUG_PROGRAM)
+release : $(RELEASE_PROGRAM)
+
+# by default on OS X we link with static libs as much as possible
+
+$(DEBUG_PROGRAM) : $(DEBUG_OBJS)
+ifeq ($(DARWIN_BUILD),yes)
+       $(LINK) -o $@ $(DEBUG_OBJS) $(EXPLICIT_LIBS)
+else
+       $(LINK) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+$(RELEASE_PROGRAM) : $(RELEASE_OBJS)
+ifeq ($(DARWIN_BUILD),yes)
+       $(LINK) -o $@ $(RELEASE_OBJS) $(EXPLICIT_LIBS)
+else
+       $(LINK) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+%.debug.o %.release.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cc
+       $(CCC) $(CFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cpp
+       $(CCC) $(CFLAGS) -c $< -o $@
+%.debug.i %.release.i : %.c
+       $(CC) $(CFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cc
+       $(CCC) $(CFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cpp
+       $(CCC) $(CFLAGS) -E $< -o $@
+
+%.debug.o : %.nasm
+       $(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ -g $< -o $@
+%.release.o : %.nasm
+       $(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ $< -o $@
+
+.PHONY : clean
+clean :
+       -rm -f $(DEBUG_OBJS) $(RELEASE_OBJS) $(OBJPATH)/*/bin/$(PROGRAM_NAME)
+
+.PHONY : depend
+depend:
+       makedepend -fMakefile.lite -- $(CFLAGS) $(INCLUDES) -- *.c *.cc *.cpp
diff --git a/build/lib.mk b/build/lib.mk
new file mode 100644 (file)
index 0000000..4480bbd
--- /dev/null
@@ -0,0 +1,124 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile fragment for building a library
+#
+
+include $(topdir)/build/config.mk
+
+ifeq ($(DARWIN_BUILD),yes)
+CC          = cc
+CCC         = c++
+else
+CC          = gcc
+CCC         = g++
+endif
+AS          = as
+NASM        = nasm
+LINK        = ar cru
+OBJPATH     = $(topdir)/obj
+LIBPATH     = $(OBJPATH)/$(BUILD)/lib
+DEBUG_LIBPATH     = $(OBJPATH)/debug/lib
+RELEASE_LIBPATH   = $(OBJPATH)/release/lib
+ifeq ($(DARWIN_BUILD),yes)
+STATIC_LIB_SUFFIX = a
+DYNAMIC_LIB_SUFFIX = dylib
+else
+STATIC_LIB_SUFFIX = a
+DYNAMIC_LIB_SUFFIX = so
+endif
+STATIC_LIB_NAME     = $(LIB_NAME).$(STATIC_LIB_SUFFIX)
+DYNAMIC_LIB_NAME    = $(LIB_NAME).$(DYNAMIC_LIB_SUFFIX)
+STATIC_LIB          = $(LIBPATH)/$(STATIC_LIB_NAME)
+DYNAMIC_LIB         = $(LIBPATH)/$(DYNAMIC_LIB_NAME)
+DEBUG_STATIC_LIB    = $(DEBUG_LIBPATH)/$(STATIC_LIB_NAME)
+DEBUG_DYNAMIC_LIB   = $(DEBUG_LIBPATH)/$(DYNAMIC_LIB_NAME)
+RELEASE_STATIC_LIB  = $(RELEASE_LIBPATH)/$(STATIC_LIB_NAME)
+RELEASE_DYNAMIC_LIB = $(RELEASE_LIBPATH)/$(DYNAMIC_LIB_NAME)
+ifeq ($(DARWIN_BUILD),yes)
+LINKD       = $(CC) -dynamiclib -flat_namespace -undefined suppress -install_name $(DYNAMIC_LIB)
+else
+LINKD       = $(CC) -shared
+endif
+
+debug   : CFLAGS = -g -O0 -DDEBUG $(CONFIG_CFLAGS) $(DEBUG_CFLAGS) -W -Wall -Wmissing-prototypes -Wstrict-prototypes -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+valgrind: CFLAGS = -g -O0 -DDEBUG $(CONFIG_CFLAGS) $(DEBUG_CFLAGS) -DFLAC__VALGRIND_TESTING -W -Wall -Wmissing-prototypes -Wstrict-prototypes -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+release : CFLAGS = -O3 -fomit-frame-pointer -funroll-loops -finline-functions -DNDEBUG $(CONFIG_CFLAGS) $(RELEASE_CFLAGS) -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Winline -DFLaC__INLINE=__inline__ -DVERSION=$(VERSION) $(DEFINES) $(INCLUDES)
+
+LFLAGS  = -L$(LIBPATH)
+
+DEBUG_OBJS = $(SRCS_C:%.c=%.debug.o) $(SRCS_CC:%.cc=%.debug.o) $(SRCS_CPP:%.cpp=%.debug.o) $(SRCS_NASM:%.nasm=%.debug.o) $(SRCS_S:%.s=%.debug.o)
+RELEASE_OBJS = $(SRCS_C:%.c=%.release.o) $(SRCS_CC:%.cc=%.release.o) $(SRCS_CPP:%.cpp=%.release.o) $(SRCS_NASM:%.nasm=%.release.o) $(SRCS_S:%.s=%.release.o)
+
+debug   : $(DEBUG_STATIC_LIB) $(DEBUG_DYNAMIC_LIB)
+valgrind: $(DEBUG_STATIC_LIB) $(DEBUG_DYNAMIC_LIB)
+release : $(RELEASE_STATIC_LIB) $(RELEASE_DYNAMIC_LIB)
+
+$(DEBUG_STATIC_LIB): $(DEBUG_OBJS)
+       $(LINK) $@ $(DEBUG_OBJS) && ranlib $@
+
+$(RELEASE_STATIC_LIB): $(RELEASE_OBJS)
+       $(LINK) $@ $(RELEASE_OBJS) && ranlib $@
+
+$(DEBUG_DYNAMIC_LIB) : $(DEBUG_OBJS)
+ifeq ($(DARWIN_BUILD),yes)
+       echo Not building dynamic lib, command is: $(LINKD) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS) -lc
+else
+       $(LINKD) -o $@ $(DEBUG_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+$(RELEASE_DYNAMIC_LIB) : $(RELEASE_OBJS)
+ifeq ($(DARWIN_BUILD),yes)
+       echo Not building dynamic lib, command is: $(LINKD) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS) -lc
+else
+       $(LINKD) -o $@ $(RELEASE_OBJS) $(LFLAGS) $(LIBS)
+endif
+
+%.debug.o %.release.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cc
+       $(CCC) $(CFLAGS) -c $< -o $@
+%.debug.o %.release.o : %.cpp
+       $(CCC) $(CFLAGS) -c $< -o $@
+%.debug.i %.release.i : %.c
+       $(CC) $(CFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cc
+       $(CCC) $(CFLAGS) -E $< -o $@
+%.debug.i %.release.i : %.cpp
+       $(CCC) $(CFLAGS) -E $< -o $@
+
+%.debug.o %.release.o : %.s
+ifeq ($(DARWIN_BUILD),yes)
+       #$(CC) -c -arch ppc -Wall -force_cpusubtype_ALL $< -o $@
+       $(AS) -arch ppc -force_cpusubtype_ALL $< -o $@
+else
+       $(AS) $< -o $@
+endif
+
+%.debug.o : %.nasm
+       $(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ -g $< -o $@
+%.release.o : %.nasm
+       $(NASM) -f elf -d OBJ_FORMAT_elf -i ia32/ $< -o $@
+
+.PHONY : clean
+clean :
+       -rm -f $(DEBUG_OBJS) $(RELEASE_OBJS) $(OBJPATH)/*/lib/$(STATIC_LIB_NAME) $(OBJPATH)/*/lib/$(DYNAMIC_LIB_NAME)
+
+.PHONY : depend
+depend:
+       makedepend -fMakefile.lite -- $(CFLAGS) $(INCLUDES) -- *.c *.cc *.cpp
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..2fc3acc
--- /dev/null
@@ -0,0 +1,1411 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-17'
+
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+## for Red Hat Linux
+if test -f /etc/redhat-release ; then
+    VENDOR=redhat ;
+else
+    VENDOR= ;
+fi
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mipseb-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha*:OpenVMS:*:*)
+       echo alpha-hp-vms
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7 && exit 0 ;;
+       esac ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c \
+         && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && exit 0
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           # avoid double evaluation of $set_cc_for_build
+           test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    *:UNICOS/mp:*:*)
+       echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' 
+       exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+       # Determine whether the default compiler uses glibc.
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #if __GLIBC__ >= 2
+       LIBC=gnu
+       #else
+       LIBC=
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    x86:Interix*:[34]*)
+       echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+       exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    cris:Linux:*:*)
+       echo cris-axis-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+       ;;
+    mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips64
+       #undef mips64el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mips64el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips64
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+       ;;
+    ppc:Linux:*:*)
+       echo powerpc-${VENDOR:-unknown}-linux-gnu
+       exit 0 ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-${VENDOR:-unknown}-linux-gnu
+       exit 0 ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu
+       exit 0 ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-${VENDOR:-unknown}-linux-gnu
+       exit 0 ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported targets: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_targets" in
+         elf32-i386)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0 ;;
+         coff-i386)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0 ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit 0 ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #ifdef __INTEL_COMPILER
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit 0 ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i*86:*:5:[78]*)
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       case `uname -p` in
+           *86) UNAME_PROCESSOR=i686 ;;
+           powerpc) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..588212b
--- /dev/null
@@ -0,0 +1,134 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* define to align allocated memory on 32-byte boundaries */
+#undef FLAC__ALIGN_MALLOC_DATA
+
+/* define if building for ia32/i386 */
+#undef FLAC__CPU_IA32
+
+/* define if building for PowerPC */
+#undef FLAC__CPU_PPC
+
+/* define if building for SPARC */
+#undef FLAC__CPU_SPARC
+
+/* define if you are compiling for PowerPC and have the 'as' assembler */
+#undef FLAC__HAS_AS
+
+/* define if you have docbook-to-man or docbook2man */
+#undef FLAC__HAS_DOCBOOK_TO_MAN
+
+/* define if you are compiling for PowerPC and have the 'gas' assembler */
+#undef FLAC__HAS_GAS
+
+/* define if you are compiling for x86 and have the NASM assembler */
+#undef FLAC__HAS_NASM
+
+/* define if you have the ogg library */
+#undef FLAC__HAS_OGG
+
+/* define to disable use of assembly code */
+#undef FLAC__NO_ASM
+
+/* define if your operating system supports SSE instructions */
+#undef FLAC__SSE_OS
+
+/* define if building for Darwin / MacOS X */
+#undef FLAC__SYS_DARWIN
+
+/* define if building for Linux */
+#undef FLAC__SYS_LINUX
+
+/* define to enable use of 3Dnow! instructions */
+#undef FLAC__USE_3DNOW
+
+/* define to enable use of Altivec instructions */
+#undef FLAC__USE_ALTIVEC
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define if you have the iconv() function. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#undef HAVE_LANGINFO_CODESET
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define as const if the declaration of iconv() needs const. */
+#undef ICONV_CONST
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of a `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
diff --git a/config.rpath b/config.rpath
new file mode 100755 (executable)
index 0000000..3f1bef3
--- /dev/null
@@ -0,0 +1,571 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+#   Copyright 1996-2005 Free Software Foundation, Inc.
+#   Taken from GNU libtool, 2001
+#   Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+#   This file is free software; the Free Software Foundation gives
+#   unlimited permission to copy and/or distribute it, with or without
+#   modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+#    CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+#    CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+#   than 256 bytes, otherwise the compiler driver will dump core. The only
+#   known workaround is to choose shorter directory names for the build
+#   directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+cc_basename=`echo "$CC" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+  wl='-Wl,'
+else
+  case "$host_os" in
+    aix*)
+      wl='-Wl,'
+      ;;
+    darwin*)
+      case "$cc_basename" in
+        xlc*)
+          wl='-Wl,'
+          ;;
+      esac
+      ;;
+    mingw* | pw32* | os2*)
+      ;;
+    hpux9* | hpux10* | hpux11*)
+      wl='-Wl,'
+      ;;
+    irix5* | irix6* | nonstopux*)
+      wl='-Wl,'
+      ;;
+    newsos6)
+      ;;
+    linux*)
+      case $cc_basename in
+        icc* | ecc*)
+          wl='-Wl,'
+          ;;
+        pgcc | pgf77 | pgf90)
+          wl='-Wl,'
+          ;;
+        ccc*)
+          wl='-Wl,'
+          ;;
+        como)
+          wl='-lopt='
+          ;;
+      esac
+      ;;
+    osf3* | osf4* | osf5*)
+      wl='-Wl,'
+      ;;
+    sco3.2v5*)
+      ;;
+    solaris*)
+      wl='-Wl,'
+      ;;
+    sunos4*)
+      wl='-Qoption ld '
+      ;;
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      wl='-Wl,'
+      ;;
+    sysv4*MP*)
+      ;;
+    unicos*)
+      wl='-Wl,'
+      ;;
+    uts4*)
+      ;;
+  esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+  case "$host_os" in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+        ld_shlibs=no
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we cannot use
+      # them.
+      ld_shlibs=no
+      ;;
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    cygwin* | mingw* | pw32*)
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    netbsd*)
+      ;;
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+        ld_shlibs=no
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    sunos4*)
+      hardcode_direct=yes
+      ;;
+    linux*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+  esac
+  if test "$ld_shlibs" = yes; then
+    # Unlike libtool, we use -rpath here, not --rpath, since the documented
+    # option of GNU ld is called -rpath, not --rpath.
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+  fi
+else
+  case "$host_os" in
+    aix3*)
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes; then
+        # Neither direct hardcoding nor static linking is supported with a
+        # broken collect2.
+        hardcode_direct=unsupported
+      fi
+      ;;
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+        # On IA64, the linker does run time linking by default, so we don't
+        # have to do anything special.
+        aix_use_runtimelinking=no
+      else
+        aix_use_runtimelinking=no
+        # Test if we are trying to use run time linking or normal
+        # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+        # need to do runtime linking.
+        case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+          for ld_flag in $LDFLAGS; do
+            if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+              aix_use_runtimelinking=yes
+              break
+            fi
+          done
+        esac
+      fi
+      hardcode_direct=yes
+      hardcode_libdir_separator=':'
+      if test "$GCC" = yes; then
+        case $host_os in aix4.[012]|aix4.[012].*)
+          collect2name=`${CC} -print-prog-name=collect2`
+          if test -f "$collect2name" && \
+            strings "$collect2name" | grep resolve_lib_name >/dev/null
+          then
+            # We have reworked collect2
+            hardcode_direct=yes
+          else
+            # We have old collect2
+            hardcode_direct=unsupported
+            hardcode_minus_L=yes
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_libdir_separator=
+          fi
+        esac
+      fi
+      # Begin _LT_AC_SYS_LIBPATH_AIX.
+      echo 'int main () { return 0; }' > conftest.c
+      ${CC} ${LDFLAGS} conftest.c -o conftest
+      aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      if test -z "$aix_libpath"; then
+        aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      fi
+      if test -z "$aix_libpath"; then
+        aix_libpath="/usr/lib:/lib"
+      fi
+      rm -f conftest.c conftest
+      # End _LT_AC_SYS_LIBPATH_AIX.
+      if test "$aix_use_runtimelinking" = yes; then
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+      else
+        if test "$host_cpu" = ia64; then
+          hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+        else
+          hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        fi
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs=no
+      ;;
+    bsdi[45]*)
+      ;;
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      libext=lib
+      ;;
+    darwin* | rhapsody*)
+      hardcode_direct=no
+      if test "$GCC" = yes ; then
+        :
+      else
+        case "$cc_basename" in
+          xlc*)
+            ;;
+          *)
+            ld_shlibs=no
+            ;;
+        esac
+      fi
+      ;;
+    dgux*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+    freebsd2.2*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    freebsd2*)
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    freebsd* | kfreebsd*-gnu | dragonfly*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    hpux9*)
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      ;;
+    hpux10* | hpux11*)
+      if test "$with_gnu_ld" = no; then
+        case "$host_cpu" in
+          hppa*64*)
+            hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+            hardcode_libdir_separator=:
+            hardcode_direct=no
+            ;;
+          ia64*)
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_direct=no
+            # hardcode_minus_L: Not really in the search PATH,
+            # but as the default location of the library.
+            hardcode_minus_L=yes
+            ;;
+          *)
+            hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+            hardcode_libdir_separator=:
+            hardcode_direct=yes
+            # hardcode_minus_L: Not really in the search PATH,
+            # but as the default location of the library.
+            hardcode_minus_L=yes
+            ;;
+        esac
+      fi
+      ;;
+    irix5* | irix6* | nonstopux*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    netbsd*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    newsos6)
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    openbsd*)
+      hardcode_direct=yes
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+        hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      else
+        case "$host_os" in
+          openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+            hardcode_libdir_flag_spec='-R$libdir'
+            ;;
+          *)
+            hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+            ;;
+        esac
+      fi
+      ;;
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      ;;
+    osf3*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    osf4* | osf5*)
+      if test "$GCC" = yes; then
+        hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+        # Both cc and cxx compiler support -rpath directly
+        hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      hardcode_libdir_separator=:
+      ;;
+    sco3.2v5*)
+      ;;
+    solaris*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      ;;
+    sunos4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    sysv4)
+      case $host_vendor in
+        sni)
+          hardcode_direct=yes # is this really true???
+          ;;
+        siemens)
+          hardcode_direct=no
+          ;;
+        motorola)
+          hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+          ;;
+      esac
+      ;;
+    sysv4.3*)
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+        ld_shlibs=yes
+      fi
+      ;;
+    sysv4.2uw2*)
+      hardcode_direct=yes
+      hardcode_minus_L=no
+      ;;
+    sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[78]* | unixware7*)
+      ;;
+    sysv5*)
+      hardcode_libdir_flag_spec=
+      ;;
+    uts4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    *)
+      ld_shlibs=no
+      ;;
+  esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+libname_spec='lib$name'
+case "$host_os" in
+  aix3*)
+    ;;
+  aix4* | aix5*)
+    ;;
+  amigaos*)
+    ;;
+  beos*)
+    ;;
+  bsdi[45]*)
+    ;;
+  cygwin* | mingw* | pw32*)
+    shrext=.dll
+    ;;
+  darwin* | rhapsody*)
+    shrext=.dylib
+    ;;
+  dgux*)
+    ;;
+  freebsd1*)
+    ;;
+  kfreebsd*-gnu)
+    ;;
+  freebsd*)
+    ;;
+  gnu*)
+    ;;
+  hpux9* | hpux10* | hpux11*)
+    case "$host_cpu" in
+      ia64*)
+        shrext=.so
+        ;;
+      hppa*64*)
+        shrext=.sl
+        ;;
+      *)
+        shrext=.sl
+        ;;
+    esac
+    ;;
+  irix5* | irix6* | nonstopux*)
+    case "$host_os" in
+      irix5* | nonstopux*)
+        libsuff= shlibsuff=
+        ;;
+      *)
+        case $LD in
+          *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+          *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+          *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+          *) libsuff= shlibsuff= ;;
+        esac
+        ;;
+    esac
+    ;;
+  linux*oldld* | linux*aout* | linux*coff*)
+    ;;
+  linux*)
+    ;;
+  knetbsd*-gnu)
+    ;;
+  netbsd*)
+    ;;
+  newsos6)
+    ;;
+  nto-qnx*)
+    ;;
+  openbsd*)
+    ;;
+  os2*)
+    libname_spec='$name'
+    shrext=.dll
+    ;;
+  osf3* | osf4* | osf5*)
+    ;;
+  sco3.2v5*)
+    ;;
+  solaris*)
+    ;;
+  sunos4*)
+    ;;
+  sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+    ;;
+  sysv4*MP*)
+    ;;
+  uts4*)
+    ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..6b2ff9f
--- /dev/null
@@ -0,0 +1,1500 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k \
+       | m32r | m68000 | m68k | m88k | mcore \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64vr | mips64vrel \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | msp430 \
+       | ns16k | ns32k \
+       | openrisc | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | s390 | s390x \
+       | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \
+       | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xscale | xstormy16 | xtensa \
+       | z8k)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* \
+       | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+       | clipper-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* \
+       | m32r-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | msp430-* \
+       | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | s390-* | s390x-* \
+       | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+       | xtensa-* \
+       | ymp-* \
+       | z8k-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nv1)
+               basic_machine=nv1-cray
+               os=-unicosmp
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       or32 | or32-*)
+               basic_machine=or32-unknown
+               os=-coff
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tic55x | c55x*)
+               basic_machine=tic55x-unknown
+               os=-coff
+               ;;
+       tic6x | c6x*)
+               basic_machine=tic6x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..0a4fffa
--- /dev/null
@@ -0,0 +1,372 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+# NOTE that for many of the AM_CONDITIONALs we use the prefix FLaC__
+# instead of FLAC__ since autoconf triggers off 'AC_' in strings
+
+AC_INIT(src/flac/main.c)
+AM_INIT_AUTOMAKE(flac, 1.2.1)
+
+# Don't automagically regenerate autoconf/automake generated files unless
+# explicitly requested.  Eases autobuilding -mdz
+AM_MAINTAINER_MODE
+
+# We need two libtools, one that builds both shared and static, and
+# one that builds only static.  This is because the resulting libtool
+# does not allow us to choose which to build at runtime.
+AM_PROG_LIBTOOL
+sed -e 's/^build_old_libs=yes/build_old_libs=no/' libtool > libtool-disable-static
+chmod +x libtool-disable-static
+
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+
+AM_PROG_AS
+AC_PROG_CXX
+AC_PROG_MAKE_SET
+
+AC_SYS_LARGEFILE
+AC_FUNC_FSEEKO
+
+AC_CHECK_SIZEOF(void*,0)
+
+#@@@ new name is AC_CONFIG_HEADERS
+AM_CONFIG_HEADER(config.h)
+
+AC_C_BIGENDIAN
+
+AC_CHECK_TYPES(socklen_t, [], [])
+
+dnl check for getopt in standard library
+dnl AC_CHECK_FUNCS(getopt_long , , [LIBOBJS="$LIBOBJS getopt.o getopt1.o"] )
+AC_CHECK_FUNCS(getopt_long, [], [])
+
+case "$host_cpu" in
+   i*86)
+      cpu_ia32=true
+      AC_DEFINE(FLAC__CPU_IA32)
+      AH_TEMPLATE(FLAC__CPU_IA32, [define if building for ia32/i386])
+      ;;
+   powerpc)
+      cpu_ppc=true
+      AC_DEFINE(FLAC__CPU_PPC)
+      AH_TEMPLATE(FLAC__CPU_PPC, [define if building for PowerPC])
+      ;;
+   sparc)
+      cpu_sparc=true
+      AC_DEFINE(FLAC__CPU_SPARC)
+      AH_TEMPLATE(FLAC__CPU_SPARC, [define if building for SPARC])
+      ;;
+esac
+AM_CONDITIONAL(FLaC__CPU_IA32, test "x$cpu_ia32" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_PPC, test "x$cpu_ppc" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_SPARC, test "x$cpu_sparc" = xtrue)
+
+case "$host" in
+   i386-*-openbsd3.[[0-3]]) OBJ_FORMAT=aoutb ;;
+   *-*-cygwin|*mingw*) OBJ_FORMAT=win32 ;;
+   *-*-darwin*) OBJ_FORMAT=macho ;;
+   *) OBJ_FORMAT=elf ;;
+esac
+AC_SUBST(OBJ_FORMAT)
+
+# only needed because of ntohl() usage, can get rid of after that's gone:
+case "$host" in
+   *-*-cygwin|*mingw*) MINGW_WINSOCK_LIBS=-lwsock32 ;;
+   *) MINGW_WINSOCK_LIBS= ;;
+esac
+AC_SUBST(MINGW_WINSOCK_LIBS)
+
+case "$host" in
+   *-pc-linux-gnu)
+      sys_linux=true
+      AC_DEFINE(FLAC__SYS_LINUX)
+      AH_TEMPLATE(FLAC__SYS_LINUX, [define if building for Linux])
+      ;;
+   *-*-darwin*)
+      sys_darwin=true
+      AC_DEFINE(FLAC__SYS_DARWIN)
+      AH_TEMPLATE(FLAC__SYS_DARWIN, [define if building for Darwin / MacOS X])
+      ;;
+esac
+AM_CONDITIONAL(FLaC__SYS_DARWIN, test "x$sys_darwin" = xtrue)
+AM_CONDITIONAL(FLaC__SYS_LINUX, test "x$sys_linux" = xtrue)
+
+if test "x$cpu_ia32" = xtrue ; then
+AC_DEFINE(FLAC__ALIGN_MALLOC_DATA)
+AH_TEMPLATE(FLAC__ALIGN_MALLOC_DATA, [define to align allocated memory on 32-byte boundaries])
+fi
+
+AC_ARG_ENABLE(asm-optimizations, AC_HELP_STRING([--disable-asm-optimizations], [Don't use any assembly optimization routines]), asm_opt=no, asm_opt=yes)
+AM_CONDITIONAL(FLaC__NO_ASM, test "x$asm_opt" = xno)
+if test "x$asm_opt" = xno ; then
+AC_DEFINE(FLAC__NO_ASM)
+AH_TEMPLATE(FLAC__NO_ASM, [define to disable use of assembly code])
+fi
+
+AC_ARG_ENABLE(debug,
+AC_HELP_STRING([--enable-debug], [Turn on debugging]),
+[case "${enableval}" in
+   yes) debug=true ;;
+   no)  debug=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
+esac],[debug=false])
+AM_CONDITIONAL(DEBUG, test "x$debug" = xtrue)
+
+AC_ARG_ENABLE(sse,
+AC_HELP_STRING([--enable-sse], [Enable SSE support by asserting that the OS supports SSE instructions]),
+[case "${enableval}" in
+   yes) sse_os=true ;;
+   no)  sse_os=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-sse) ;;
+esac],[sse_os=false])
+AM_CONDITIONAL(FLaC__SSE_OS, test "x$sse_os" = xtrue)
+if test "x$sse_os" = xtrue ; then
+AC_DEFINE(FLAC__SSE_OS)
+AH_TEMPLATE(FLAC__SSE_OS, [define if your operating system supports SSE instructions])
+fi
+
+AC_ARG_ENABLE(3dnow,
+AC_HELP_STRING([--disable-3dnow], [Disable 3DNOW! optimizations]),
+[case "${enableval}" in
+   yes) use_3dnow=true ;;
+   no)  use_3dnow=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-3dnow) ;;
+esac],[use_3dnow=true])
+AM_CONDITIONAL(FLaC__USE_3DNOW, test "x$use_3dnow" = xtrue)
+if test "x$use_3dnow" = xtrue ; then
+AC_DEFINE(FLAC__USE_3DNOW)
+AH_TEMPLATE(FLAC__USE_3DNOW, [define to enable use of 3Dnow! instructions])
+fi
+
+AC_ARG_ENABLE(altivec,
+AC_HELP_STRING([--disable-altivec], [Disable Altivec optimizations]),
+[case "${enableval}" in
+   yes) use_altivec=true ;;
+   no)  use_altivec=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-altivec) ;;
+esac],[use_altivec=true])
+AM_CONDITIONAL(FLaC__USE_ALTIVEC, test "x$use_altivec" = xtrue)
+if test "x$use_altivec" = xtrue ; then
+AC_DEFINE(FLAC__USE_ALTIVEC)
+AH_TEMPLATE(FLAC__USE_ALTIVEC, [define to enable use of Altivec instructions])
+fi
+
+AC_ARG_ENABLE(thorough-tests,
+AC_HELP_STRING([--disable-thorough-tests], [Disable thorough (long) testing, do only basic tests]),
+[case "${enableval}" in
+   yes) thorough_tests=true ;;
+   no)  thorough_tests=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-thorough-tests) ;;
+esac],[thorough_tests=true])
+AC_ARG_ENABLE(exhaustive-tests,
+AC_HELP_STRING([--enable-exhaustive-tests], [Enable exhaustive testing (VERY long)]),
+[case "${enableval}" in
+   yes) exhaustive_tests=true ;;
+   no)  exhaustive_tests=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-exhaustive-tests) ;;
+esac],[exhaustive_tests=false])
+if test "x$thorough_tests" = xfalse ; then
+FLAC__TEST_LEVEL=0
+elif test "x$exhaustive_tests" = xfalse ; then
+FLAC__TEST_LEVEL=1
+else
+FLAC__TEST_LEVEL=2
+fi
+AC_SUBST(FLAC__TEST_LEVEL)
+
+AC_ARG_ENABLE(valgrind-testing,
+AC_HELP_STRING([--enable-valgrind-testing], [Run all tests inside Valgrind]),
+[case "${enableval}" in
+   yes) FLAC__TEST_WITH_VALGRIND=yes ;;
+   no)  FLAC__TEST_WITH_VALGRIND=no ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind-testing) ;;
+esac],[FLAC__TEST_WITH_VALGRIND=no])
+AC_SUBST(FLAC__TEST_WITH_VALGRIND)
+
+AC_ARG_ENABLE(doxygen-docs,
+AC_HELP_STRING([--disable-doxygen-docs], [Disable API documentation building via Doxygen]),
+[case "${enableval}" in
+   yes) enable_doxygen_docs=true ;;
+   no)  enable_doxygen_docs=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-doxygen-docs) ;;
+esac],[enable_doxygen_docs=true])
+if test "x$enable_doxygen_docs" != xfalse ; then
+   AC_CHECK_PROGS(DOXYGEN, doxygen)
+fi
+AM_CONDITIONAL(FLaC__HAS_DOXYGEN, test -n "$DOXYGEN")
+
+AC_ARG_ENABLE(local-xmms-plugin,
+AC_HELP_STRING([--enable-local-xmms-plugin], [Install XMMS plugin to ~/.xmms/Plugins instead of system location]),
+[case "${enableval}" in
+   yes) install_xmms_plugin_locally=true ;;
+   no)  install_xmms_plugin_locally=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-local-xmms-plugin) ;;
+esac],[install_xmms_plugin_locally=false])
+AM_CONDITIONAL(FLaC__INSTALL_XMMS_PLUGIN_LOCALLY, test "x$install_xmms_plugin_locally" = xtrue)
+
+AC_ARG_ENABLE(xmms-plugin,
+AC_HELP_STRING([--disable-xmms-plugin], [Do not build XMMS plugin]),
+[case "${enableval}" in
+   yes) enable_xmms_plugin=true ;;
+   no)  enable_xmms_plugin=false ;;
+   *) AC_MSG_ERROR(bad value ${enableval} for --enable-xmms-plugin) ;;
+esac],[enable_xmms_plugin=true])
+if test "x$enable_xmms_plugin" != xfalse ; then
+   AM_PATH_XMMS(0.9.5.1, , AC_MSG_WARN([*** XMMS >= 0.9.5.1 not installed - XMMS support will not be built]))
+fi
+AM_CONDITIONAL(FLaC__HAS_XMMS, test -n "$XMMS_INPUT_PLUGIN_DIR")
+
+dnl build FLAC++ or not
+AC_ARG_ENABLE([cpplibs],
+AC_HELP_STRING([--disable-cpplibs], [Do not build libFLAC++]),
+[case "${enableval}" in
+   yes) disable_cpplibs=false ;;
+   no)  disable_cpplibs=true ;;
+   *)   AC_MSG_ERROR(bad value ${enableval} for --enable-cpplibs) ;;
+esac], [disable_cpplibs=false])
+AM_CONDITIONAL(FLaC__WITH_CPPLIBS, [test "x$disable_cpplibs" != xtrue])
+
+dnl check for ogg library
+AC_ARG_ENABLE([ogg],
+   AC_HELP_STRING([--disable-ogg], [Disable ogg support (default: test for libogg)]),
+   [ want_ogg=$enableval ], [ want_ogg=yes ] )
+
+if test "x$want_ogg" != "xno"; then
+   XIPH_PATH_OGG(have_ogg=yes, AC_MSG_WARN([*** Ogg development enviroment not installed - Ogg support will not be built]))
+fi
+AM_CONDITIONAL(FLaC__HAS_OGG, [test "x$have_ogg" = xyes])
+if test "x$have_ogg" = xyes ; then
+AC_DEFINE(FLAC__HAS_OGG)
+AH_TEMPLATE(FLAC__HAS_OGG, [define if you have the ogg library])
+fi
+
+dnl check for i18n(internationalization); these are from libiconv/gettext
+AM_ICONV
+AM_LANGINFO_CODESET
+
+AC_CHECK_PROGS(DOCBOOK_TO_MAN, docbook-to-man docbook2man)
+AM_CONDITIONAL(FLaC__HAS_DOCBOOK_TO_MAN, test -n "$DOCBOOK_TO_MAN")
+if test -n "$DOCBOOK_TO_MAN" ; then
+AC_DEFINE(FLAC__HAS_DOCBOOK_TO_MAN)
+AH_TEMPLATE(FLAC__HAS_DOCBOOK_TO_MAN, [define if you have docbook-to-man or docbook2man])
+fi
+
+# only matters for x86
+AC_CHECK_PROGS(NASM, nasm)
+AM_CONDITIONAL(FLaC__HAS_NASM, test -n "$NASM")
+if test -n "$NASM" ; then
+AC_DEFINE(FLAC__HAS_NASM)
+AH_TEMPLATE(FLAC__HAS_NASM, [define if you are compiling for x86 and have the NASM assembler])
+fi
+
+# only matters for PowerPC
+AC_CHECK_PROGS(AS, as, as)
+AC_CHECK_PROGS(GAS, gas, gas)
+
+# try -v (apple as) and --version (gas) at the same time
+test "$AS" = "as" && as --version -v < /dev/null 2>&1 | grep Apple >/dev/null || AS=gas
+
+AM_CONDITIONAL(FLaC__HAS_AS, test "$AS" = "as")
+AM_CONDITIONAL(FLaC__HAS_GAS, test "$AS" = "gas")
+if test "$AS" = "as" ; then
+AC_DEFINE(FLAC__HAS_AS)
+AH_TEMPLATE(FLAC__HAS_AS, [define if you are compiling for PowerPC and have the 'as' assembler])
+fi
+if test "$AS" = "gas" ; then
+# funniest. macro. ever.
+AC_DEFINE(FLAC__HAS_GAS)
+AH_TEMPLATE(FLAC__HAS_GAS, [define if you are compiling for PowerPC and have the 'gas' assembler])
+fi
+
+CPPFLAGS='-I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include'" $CPPFLAGS"
+if test "x$debug" = xtrue; then
+   CPPFLAGS="-DDEBUG $CPPFLAGS"
+   CFLAGS="-g $CFLAGS"
+else
+   CPPFLAGS="-DNDEBUG $CPPFLAGS"
+   if test "x$GCC" = xyes; then
+      CPPFLAGS="-DFLaC__INLINE=__inline__ $CPPFLAGS"
+      CFLAGS="-O3 -funroll-loops -finline-functions -Wall -W -Winline $CFLAGS"
+   fi
+fi
+
+#@@@
+AM_CONDITIONAL(FLaC__HAS_AS__TEMPORARILY_DISABLED, test "yes" = "no")
+AM_CONDITIONAL(FLaC__HAS_GAS__TEMPORARILY_DISABLED, test "yes" = "no")
+
+AC_CONFIG_FILES([ \
+   Makefile \
+   src/Makefile \
+   src/libFLAC/Makefile \
+   src/libFLAC/flac.pc \
+   src/libFLAC/ia32/Makefile \
+   src/libFLAC/ppc/Makefile \
+   src/libFLAC/ppc/as/Makefile \
+   src/libFLAC/ppc/gas/Makefile \
+   src/libFLAC/include/Makefile \
+   src/libFLAC/include/private/Makefile \
+   src/libFLAC/include/protected/Makefile \
+   src/libFLAC++/Makefile \
+   src/libFLAC++/flac++.pc \
+   src/flac/Makefile \
+   src/metaflac/Makefile \
+   src/monkeys_audio_utilities/Makefile \
+   src/monkeys_audio_utilities/flac_mac/Makefile \
+   src/monkeys_audio_utilities/flac_ren/Makefile \
+   src/plugin_common/Makefile \
+   src/plugin_winamp2/Makefile \
+   src/plugin_winamp2/include/Makefile \
+   src/plugin_winamp2/include/winamp2/Makefile \
+   src/plugin_xmms/Makefile \
+   src/share/Makefile \
+   src/share/getopt/Makefile \
+   src/share/grabbag/Makefile \
+   src/share/replaygain_analysis/Makefile \
+   src/share/replaygain_synthesis/Makefile \
+   src/share/replaygain_synthesis/include/Makefile \
+   src/share/replaygain_synthesis/include/private/Makefile \
+   src/share/utf8/Makefile \
+   src/test_grabbag/Makefile \
+   src/test_grabbag/cuesheet/Makefile \
+   src/test_grabbag/picture/Makefile \
+   src/test_libs_common/Makefile \
+   src/test_libFLAC/Makefile \
+   src/test_libFLAC++/Makefile \
+   src/test_seeking/Makefile \
+   src/test_streams/Makefile \
+   examples/Makefile \
+   examples/c/Makefile \
+   examples/c/decode/Makefile \
+   examples/c/decode/file/Makefile \
+   examples/c/encode/Makefile \
+   examples/c/encode/file/Makefile \
+   examples/cpp/Makefile \
+   examples/cpp/decode/Makefile \
+   examples/cpp/decode/file/Makefile \
+   examples/cpp/encode/Makefile \
+   examples/cpp/encode/file/Makefile \
+   include/Makefile \
+   include/FLAC/Makefile \
+   include/FLAC++/Makefile \
+   include/share/Makefile \
+   include/share/grabbag/Makefile \
+   include/test_libs_common/Makefile \
+   m4/Makefile \
+   man/Makefile \
+])
+AC_OUTPUT
diff --git a/debian/changelog b/debian/changelog
new file mode 100755 (executable)
index 0000000..0ed1e55
--- /dev/null
@@ -0,0 +1,5 @@
+libflac (1.2.1) unstable; urgency=low
+
+  * Initial Version.
+
+ -- Prince Kumar Dubey <prince.dubey@samsung.com>  Thur, 13 Oct 2011 15:00:00 +0900
\ No newline at end of file
diff --git a/debian/compat b/debian/compat
new file mode 100755 (executable)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100755 (executable)
index 0000000..aa89a17
--- /dev/null
@@ -0,0 +1,21 @@
+Source: libflac
+Section: libs
+Priority: optional
+Uploaders: Prince Kumar Dubey<prince.dubey@samsung.com>
+Maintainer: Josh Coalson
+Build-Depends: cdbs, libogg-dev, pkg-config, libtool
+Standards-Version: 1.2.1
+Homepage: http://flac.sourceforge.net/
+
+Package: libflac
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Suggests: libFLAC (= ${binary:Version})
+Description: FLAC is an Open Source lossless audio codec
+
+Package: libflac-dev
+Architecture: any
+Section: libdevel
+Depends: ${misc:Depends}, libflac (= ${binary:Version})
+Description: FLAC is an Open Source lossless audio codec
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100755 (executable)
index 0000000..1e2c56a
--- /dev/null
@@ -0,0 +1,38 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This file is part the FLAC project.  FLAC is comprised of several
+ * components distributed under difference licenses.  The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution).  All other programs, libraries, and
+ * plugins are distributed under the LGPL or GPL (see COPYING.LGPL and
+ * COPYING.GPL).  The documentation is distributed under the Gnu FDL (see
+ * COPYING.FDL).  Each file in the FLAC distribution contains at the top the
+ * terms under which it may be distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above.  See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio
+codec developed by Josh Coalson.
+
+FLAC is comprised of
+  * `libFLAC', a library which implements reference encoders and
+    decoders for native FLAC and Ogg FLAC, and a metadata interface
+  * `libFLAC++', a C++ object wrapper library around libFLAC
+  * `flac', a command-line program for encoding and decoding files
+  * `metaflac', a command-line program for viewing and editing FLAC
+    metadata
+  * player plugins for XMMS and Winamp
+  * user and API documentation
+
+The libraries (libFLAC, libFLAC++) are
+licensed under Xiph.org's BSD-like license (see COPYING.Xiph).  All other
+programs and plugins are licensed under the GNU General Public License
+(see COPYING.GPL).  The documentation is licensed under the GNU Free
+Documentation License (see COPYING.FDL).
+
+
diff --git a/debian/libflac-dev.install b/debian/libflac-dev.install
new file mode 100644 (file)
index 0000000..1b7c7b1
--- /dev/null
@@ -0,0 +1,5 @@
+debian/tmp/usr/include/*
+debian/tmp/usr/lib/lib*.la
+debian/tmp/usr/lib/lib*.a
+debian/tmp/usr/lib/libFLAC.so
+debian/tmp/usr/lib/pkgconfig/*
\ No newline at end of file
diff --git a/debian/libflac.install b/debian/libflac.install
new file mode 100755 (executable)
index 0000000..f0ee48a
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/lib/libFLAC.so.*
\ No newline at end of file
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..65d2097
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/debhelper.mk
+
+DEB_CONFIGURE_SCRIPT := ./autogen.sh
+DEB_MAKE_CLEAN_TARGET := distclean
+DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr --disable-asm-optimizations --disable-dependency-tracking --disable-3dnow --disable-thorough-tests --disable-doxygen-docs --disable-xmms-plugin --disable-cpplibs
+
+CFLAGS += -fvisibility=default -fPIC -W -Wall -Wextra
+LDFLAGS += -fvisibility=default -Wl,--hash-style=both -Wl,--as-needed
+
+clean::
+       [ ! -f Makefile ] || make distclean
+       rm -f libflac*.tar.bz2 libflac-*.tar.bz2.cdbs-config_list
diff --git a/depcomp b/depcomp
new file mode 100755 (executable)
index 0000000..edb5d38
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,479 @@
+#! /bin/sh
+
+# depcomp - compile a program generating dependencies as side-effects
+# Copyright 1999, 2000, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+# `libtool' can also be set to `yes' or `no'.
+
+if test -z "$depfile"; then
+   base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
+   dir=`echo "$object" | sed 's,/.*$,/,'`
+   if test "$dir" = "$object"; then
+      dir=
+   fi
+   # FIXME: should be _deps on DOS.
+   depfile="$dir.deps/$base"
+fi
+
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+  "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> $depfile
+    echo >> $depfile
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> $depfile
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+  tmpdepfile="$stripped.u"
+  if test "$libtool" = yes; then
+    "$@" -Wc,-M
+  else
+    "$@" -M
+  fi
+  stat=$?
+
+  if test -f "$tmpdepfile"; then :
+  else
+    stripped=`echo "$stripped" | sed 's,^.*/,,'`
+    tmpdepfile="$stripped.u"
+  fi
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+
+  if test -f "$tmpdepfile"; then
+    outname="$stripped.o"
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+    sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler understands `-MD -MF file'.  However on
+  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want:
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using \ :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+    sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      tmpdepfile1="$dir.libs/$base.lo.d"
+      tmpdepfile2="$dir.libs/$base.d"
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1="$dir$base.o.d"
+      tmpdepfile2="$dir$base.d"
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2"
+      exit $stat
+   fi
+
+   if test -f "$tmpdepfile1"; then
+      tmpdepfile="$tmpdepfile1"
+   else
+      tmpdepfile="$tmpdepfile2"
+   fi
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a tab and a space in the [].
+      sed -e 's,^.*\.[a-z]*:[   ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for `:'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no
+  for arg in "$@"; do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix="`echo $object | sed 's/^.*\././'`"
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o,
+  # because we must use -o when running libtool.
+  "$@" || exit $?
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+       set fnord "$@"
+       shift
+       shift
+       ;;
+    *)
+       set fnord "$@" "$arg"
+       shift
+       shift
+       ;;
+    esac
+  done
+  "$@" -E |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::   \1 \\:p' >> "$depfile"
+  echo "       " >> "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644 (file)
index 0000000..64a49f3
--- /dev/null
@@ -0,0 +1,27 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = cpp
+endif
+
+SUBDIRS = c $(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+       examples.dsp \
+       Makefile.lite \
+       README
diff --git a/examples/Makefile.lite b/examples/Makefile.lite
new file mode 100644 (file)
index 0000000..abfe657
--- /dev/null
@@ -0,0 +1,49 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+.PHONY: all example_c_decode_file example_c_encode_file example_cpp_decode_file example_cpp_encode_file
+all: example_c_decode_file example_c_encode_file example_cpp_decode_file example_cpp_encode_file
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+example_c_decode_file:
+       (cd c/decode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_c_encode_file:
+       (cd c/encode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_cpp_decode_file:
+       (cd cpp/decode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+example_cpp_encode_file:
+       (cd cpp/encode/file && $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+       -(cd c/decode/file && $(MAKE) -f Makefile.lite clean)
+       -(cd c/encode/file && $(MAKE) -f Makefile.lite clean)
+       -(cd cpp/decode/file && $(MAKE) -f Makefile.lite clean)
+       -(cd cpp/encode/file && $(MAKE) -f Makefile.lite clean)
diff --git a/examples/README b/examples/README
new file mode 100644 (file)
index 0000000..0c51ff9
--- /dev/null
@@ -0,0 +1,12 @@
+Here are several small example programs that use the libraries in different
+ways.
+
+The "c" directory has programs that are all in C and use libFLAC.
+
+The "cpp" directory has analogous programs that are all in C++ and use libFLAC++. 
+
+The programs are:
+c/decode/file/ - example_c_decode_file - Simple FLAC file decoder using libFLAC
+c/encode/file/ - example_c_encode_file - Simple FLAC file encoder using libFLAC
+cpp/decode/file/ - example_cpp_decode_file - Simple FLAC file decoder using libFLAC++
+cpp/encode/file/ - example_cpp_encode_file - Simple FLAC file encoder using libFLAC++
diff --git a/examples/c/Makefile.am b/examples/c/Makefile.am
new file mode 100644 (file)
index 0000000..b88dca6
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = decode encode
diff --git a/examples/c/decode/Makefile.am b/examples/c/decode/Makefile.am
new file mode 100644 (file)
index 0000000..35bb987
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/c/decode/file/Makefile.am b/examples/c/decode/file/Makefile.am
new file mode 100644 (file)
index 0000000..eb18ceb
--- /dev/null
@@ -0,0 +1,29 @@
+#  example_c_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       example_c_decode_file.dsp \
+       example_c_decode_file.vcproj
+
+noinst_PROGRAMS = example_c_decode_file
+example_c_decode_file_LDADD = \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+example_c_decode_file_SOURCES = main.c
diff --git a/examples/c/decode/file/Makefile.lite b/examples/c/decode/file/Makefile.lite
new file mode 100644 (file)
index 0000000..e5070c1
--- /dev/null
@@ -0,0 +1,39 @@
+#  example_c_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007  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
+#
+
+topdir = ../../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = example_c_decode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/c/decode/file/example_c_decode_file.dsp b/examples/c/decode/file/example_c_decode_file.dsp
new file mode 100644 (file)
index 0000000..fe0a7d2
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="example_c_decode_file" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=example_c_decode_file - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_c_decode_file.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_c_decode_file.mak" CFG="example_c_decode_file - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "example_c_decode_file - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "example_c_decode_file - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "example_c_decode_file - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\..\obj\release\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "example_c_decode_file - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\..\obj\debug\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "example_c_decode_file - Win32 Release"\r
+# Name "example_c_decode_file - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/examples/c/decode/file/example_c_decode_file.vcproj b/examples/c/decode/file/example_c_decode_file.vcproj
new file mode 100644 (file)
index 0000000..ec40ece
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="example_c_decode_file"\r
+       ProjectGUID="{4cefbd00-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="example_c_decode_file"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{39992580-89DB-4b41-8E8B-625F9E28BEBF}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/examples/c/decode/file/main.c b/examples/c/decode/file/main.c
new file mode 100644 (file)
index 0000000..20fafa2
--- /dev/null
@@ -0,0 +1,190 @@
+/* example_c_decode_file - Simple FLAC file decoder using libFLAC
+ * Copyright (C) 2007  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.
+ */
+
+/*
+ * This example shows how to use libFLAC to decode a FLAC file to a WAVE
+ * file.  It only supports 16-bit stereo files.
+ *
+ * Complete API documentation can be found at:
+ *   http://flac.sourceforge.net/api/
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "FLAC/stream_decoder.h"
+
+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__uint64 total_samples = 0;
+static unsigned sample_rate = 0;
+static unsigned channels = 0;
+static unsigned bps = 0;
+
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF
+       ;
+}
+
+static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+       return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x >> 16, f) != EOF &&
+               fputc(x >> 24, f) != EOF
+       ;
+}
+
+int main(int argc, char *argv[])
+{
+       FLAC__bool ok = true;
+       FLAC__StreamDecoder *decoder = 0;
+       FLAC__StreamDecoderInitStatus init_status;
+       FILE *fout;
+
+       if(argc != 3) {
+               fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]);
+               return 1;
+       }
+
+       if((fout = fopen(argv[2], "wb")) == NULL) {
+               fprintf(stderr, "ERROR: opening %s for output\n", argv[2]);
+               return 1;
+       }
+
+       if((decoder = FLAC__stream_decoder_new()) == NULL) {
+               fprintf(stderr, "ERROR: allocating decoder\n");
+               fclose(fout);
+               return 1;
+       }
+
+       (void)FLAC__stream_decoder_set_md5_checking(decoder, true);
+
+       init_status = FLAC__stream_decoder_init_file(decoder, argv[1], write_callback, metadata_callback, error_callback, /*client_data=*/fout);
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
+               ok = false;
+       }
+
+       if(ok) {
+               ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
+               fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED");
+               fprintf(stderr, "   state: %s\n", FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(decoder)]);
+       }
+
+       FLAC__stream_decoder_delete(decoder);
+       fclose(fout);
+
+       return 0;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       FILE *f = (FILE*)client_data;
+       const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8));
+       size_t i;
+
+       (void)decoder;
+
+       if(total_samples == 0) {
+               fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+       if(channels != 2 || bps != 16) {
+               fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+
+       /* write WAVE header before we write the first frame */
+       if(frame->header.number.sample_number == 0) {
+               if(
+                       fwrite("RIFF", 1, 4, f) < 4 ||
+                       !write_little_endian_uint32(f, total_size + 36) ||
+                       fwrite("WAVEfmt ", 1, 8, f) < 8 ||
+                       !write_little_endian_uint32(f, 16) ||
+                       !write_little_endian_uint16(f, 1) ||
+                       !write_little_endian_uint16(f, (FLAC__uint16)channels) ||
+                       !write_little_endian_uint32(f, sample_rate) ||
+                       !write_little_endian_uint32(f, sample_rate * channels * (bps/8)) ||
+                       !write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */
+                       !write_little_endian_uint16(f, (FLAC__uint16)bps) ||
+                       fwrite("data", 1, 4, f) < 4 ||
+                       !write_little_endian_uint32(f, total_size)
+               ) {
+                       fprintf(stderr, "ERROR: write error\n");
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+
+       /* write decoded PCM samples */
+       for(i = 0; i < frame->header.blocksize; i++) {
+               if(
+                       !write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) ||  /* left channel */
+                       !write_little_endian_int16(f, (FLAC__int16)buffer[1][i])     /* right channel */
+               ) {
+                       fprintf(stderr, "ERROR: write error\n");
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       (void)decoder, (void)client_data;
+
+       /* print some stats */
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               /* save for later */
+               total_samples = metadata->data.stream_info.total_samples;
+               sample_rate = metadata->data.stream_info.sample_rate;
+               channels = metadata->data.stream_info.channels;
+               bps = metadata->data.stream_info.bits_per_sample;
+
+               fprintf(stderr, "sample rate    : %u Hz\n", sample_rate);
+               fprintf(stderr, "channels       : %u\n", channels);
+               fprintf(stderr, "bits per sample: %u\n", bps);
+#ifdef _MSC_VER
+               fprintf(stderr, "total samples  : %I64u\n", total_samples);
+#else
+               fprintf(stderr, "total samples  : %llu\n", total_samples);
+#endif
+       }
+}
+
+void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       (void)decoder, (void)client_data;
+
+       fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
diff --git a/examples/c/encode/Makefile.am b/examples/c/encode/Makefile.am
new file mode 100644 (file)
index 0000000..35bb987
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/c/encode/file/Makefile.am b/examples/c/encode/file/Makefile.am
new file mode 100644 (file)
index 0000000..be98e85
--- /dev/null
@@ -0,0 +1,29 @@
+#  example_c_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       example_c_encode_file.dsp \
+       example_c_encode_file.vcproj
+
+noinst_PROGRAMS = example_c_encode_file
+example_c_encode_file_LDADD = \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+example_c_encode_file_SOURCES = main.c
diff --git a/examples/c/encode/file/Makefile.lite b/examples/c/encode/file/Makefile.lite
new file mode 100644 (file)
index 0000000..d8be326
--- /dev/null
@@ -0,0 +1,39 @@
+#  example_c_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007  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
+#
+
+topdir = ../../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = example_c_encode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/c/encode/file/example_c_encode_file.dsp b/examples/c/encode/file/example_c_encode_file.dsp
new file mode 100644 (file)
index 0000000..8b22bc4
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="example_c_encode_file" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=example_c_encode_file - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_c_encode_file.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_c_encode_file.mak" CFG="example_c_encode_file - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "example_c_encode_file - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "example_c_encode_file - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "example_c_encode_file - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\..\obj\release\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "example_c_encode_file - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\..\obj\debug\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "example_c_encode_file - Win32 Release"\r
+# Name "example_c_encode_file - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/examples/c/encode/file/example_c_encode_file.vcproj b/examples/c/encode/file/example_c_encode_file.vcproj
new file mode 100644 (file)
index 0000000..e4e7a30
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="example_c_encode_file"\r
+       ProjectGUID="{4cefbd01-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="example_c_encode_file"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{39992580-89DB-4b41-8E8B-625F9E28BEBF}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC727F1-C7A5-1376-A061-2AF2D742A2F0}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/examples/c/encode/file/main.c b/examples/c/encode/file/main.c
new file mode 100644 (file)
index 0000000..d1037e3
--- /dev/null
@@ -0,0 +1,173 @@
+/* example_c_encode_file - Simple FLAC file encoder using libFLAC
+ * Copyright (C) 2007  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.
+ */
+
+/*
+ * This example shows how to use libFLAC to encode a WAVE file to a FLAC
+ * file.  It only supports 16-bit stereo files in canonical WAVE format.
+ *
+ * Complete API documentation can be found at:
+ *   http://flac.sourceforge.net/api/
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/metadata.h"
+#include "FLAC/stream_encoder.h"
+
+static void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+#define READSIZE 1024
+
+static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
+static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
+static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
+
+int main(int argc, char *argv[])
+{
+       FLAC__bool ok = true;
+       FLAC__StreamEncoder *encoder = 0;
+       FLAC__StreamEncoderInitStatus init_status;
+       FLAC__StreamMetadata *metadata[2];
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+       FILE *fin;
+       unsigned sample_rate = 0;
+       unsigned channels = 0;
+       unsigned bps = 0;
+
+       if(argc != 3) {
+               fprintf(stderr, "usage: %s infile.wav outfile.flac\n", argv[0]);
+               return 1;
+       }
+
+       if((fin = fopen(argv[1], "rb")) == NULL) {
+               fprintf(stderr, "ERROR: opening %s for output\n", argv[1]);
+               return 1;
+       }
+
+       /* read wav header and validate it */
+       if(
+               fread(buffer, 1, 44, fin) != 44 ||
+               memcmp(buffer, "RIFF", 4) ||
+               memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
+               memcmp(buffer+32, "\004\000\020\000data", 8)
+       ) {
+               fprintf(stderr, "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n");
+               fclose(fin);
+               return 1;
+       }
+       sample_rate = ((((((unsigned)buffer[27] << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24];
+       channels = 2;
+       bps = 16;
+       total_samples = (((((((unsigned)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
+   
+       /* allocate the encoder */
+       if((encoder = FLAC__stream_encoder_new()) == NULL) {
+               fprintf(stderr, "ERROR: allocating encoder\n");
+               fclose(fin);
+               return 1;
+       }
+
+       ok &= FLAC__stream_encoder_set_verify(encoder, true);
+       ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
+       ok &= FLAC__stream_encoder_set_channels(encoder, channels);
+       ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
+       ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
+       ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);
+
+       /* now add some metadata; we'll add some tags and a padding block */
+       if(ok) {
+               if(
+                       (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
+                       (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
+                       /* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
+                       !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") ||
+                       !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */
+                       !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") ||
+                       !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false)
+               ) {
+                       fprintf(stderr, "ERROR: out of memory or tag error\n");
+                       ok = false;
+               }
+
+               metadata[1]->length = 1234; /* set the padding length */
+
+               ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
+       }
+
+       /* initialize encoder */
+       if(ok) {
+               init_status = FLAC__stream_encoder_init_file(encoder, argv[2], progress_callback, /*client_data=*/NULL);
+               if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+                       fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
+                       ok = false;
+               }
+       }
+
+       /* read blocks of samples from WAVE file and feed to encoder */
+       if(ok) {
+               size_t left = (size_t)total_samples;
+               while(ok && left) {
+                       size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
+                       if(fread(buffer, channels*(bps/8), need, fin) != need) {
+                               fprintf(stderr, "ERROR: reading from WAVE file\n");
+                               ok = false;
+                       }
+                       else {
+                               /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
+                               size_t i;
+                               for(i = 0; i < need*channels; i++) {
+                                       /* inefficient but simple and works on big- or little-endian machines */
+                                       pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
+                               }
+                               /* feed samples to encoder */
+                               ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
+                       }
+                       left -= need;
+               }
+       }
+
+       ok &= FLAC__stream_encoder_finish(encoder);
+
+       fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED");
+       fprintf(stderr, "   state: %s\n", FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]);
+
+       /* now that encoding is finished, the metadata can be freed */
+       FLAC__metadata_object_delete(metadata[0]);
+       FLAC__metadata_object_delete(metadata[1]);
+
+       FLAC__stream_encoder_delete(encoder);
+       fclose(fin);
+
+       return 0;
+}
+
+void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+       (void)encoder, (void)client_data;
+
+#ifdef _MSC_VER
+       fprintf(stderr, "wrote %I64u bytes, %I64u/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+#else
+       fprintf(stderr, "wrote %llu bytes, %llu/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+#endif
+}
diff --git a/examples/cpp/Makefile.am b/examples/cpp/Makefile.am
new file mode 100644 (file)
index 0000000..b88dca6
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = decode encode
diff --git a/examples/cpp/decode/Makefile.am b/examples/cpp/decode/Makefile.am
new file mode 100644 (file)
index 0000000..35bb987
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/cpp/decode/file/Makefile.am b/examples/cpp/decode/file/Makefile.am
new file mode 100644 (file)
index 0000000..a0d3dbf
--- /dev/null
@@ -0,0 +1,30 @@
+#  example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       example_cpp_decode_file.dsp \
+       example_cpp_decode_file.vcproj
+
+noinst_PROGRAMS = example_cpp_decode_file
+example_cpp_decode_file_LDADD = \
+       $(top_builddir)/src/libFLAC++/libFLAC++.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+example_cpp_decode_file_SOURCES = main.cpp
diff --git a/examples/cpp/decode/file/Makefile.lite b/examples/cpp/decode/file/Makefile.lite
new file mode 100644 (file)
index 0000000..abc93e8
--- /dev/null
@@ -0,0 +1,41 @@
+#  example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+#  Copyright (C) 2007  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
+#
+
+topdir = ../../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = example_cpp_decode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lFLAC++ -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_CPP = main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/cpp/decode/file/example_cpp_decode_file.dsp b/examples/cpp/decode/file/example_cpp_decode_file.dsp
new file mode 100644 (file)
index 0000000..7c16209
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="example_cpp_decode_file" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=example_cpp_decode_file - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_cpp_decode_file.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_cpp_decode_file.mak" CFG="example_cpp_decode_file - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "example_cpp_decode_file - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "example_cpp_decode_file - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "example_cpp_decode_file - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\..\obj\release\lib\libFLAC++_static.lib ..\..\..\..\obj\release\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "example_cpp_decode_file - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\..\obj\debug\lib\libFLAC++_static.lib ..\..\..\..\obj\debug\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "example_cpp_decode_file - Win32 Release"\r
+# Name "example_cpp_decode_file - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/examples/cpp/decode/file/example_cpp_decode_file.vcproj b/examples/cpp/decode/file/example_cpp_decode_file.vcproj
new file mode 100644 (file)
index 0000000..93e911e
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="example_cpp_decode_file"\r
+       ProjectGUID="{4cefbe00-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="example_cpp_decode_file"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93292580-829B-b441-E8B8-65A95828BEB0}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{9C7247F1-CA27-1761-A016-0F27452AD2F0}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/examples/cpp/decode/file/main.cpp b/examples/cpp/decode/file/main.cpp
new file mode 100644 (file)
index 0000000..5614050
--- /dev/null
@@ -0,0 +1,189 @@
+/* example_cpp_decode_file - Simple FLAC file decoder using libFLAC
+ * Copyright (C) 2007  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.
+ */
+
+/*
+ * This example shows how to use libFLAC++ to decode a FLAC file to a WAVE
+ * file.  It only supports 16-bit stereo files.
+ *
+ * Complete API documentation can be found at:
+ *   http://flac.sourceforge.net/api/
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "FLAC++/decoder.h"
+
+static FLAC__uint64 total_samples = 0;
+static unsigned sample_rate = 0;
+static unsigned channels = 0;
+static unsigned bps = 0;
+
+static bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF
+       ;
+}
+
+static bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+       return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x >> 16, f) != EOF &&
+               fputc(x >> 24, f) != EOF
+       ;
+}
+
+class OurDecoder: public FLAC::Decoder::File {
+public:
+       OurDecoder(FILE *f_): FLAC::Decoder::File(), f(f_) { }
+protected:
+       FILE *f;
+
+       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+       virtual void error_callback(::FLAC__StreamDecoderErrorStatus status);
+};
+
+int main(int argc, char *argv[])
+{
+       bool ok = true;
+       FILE *fout;
+
+       if(argc != 3) {
+               fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]);
+               return 1;
+       }
+
+       if((fout = fopen(argv[2], "wb")) == NULL) {
+               fprintf(stderr, "ERROR: opening %s for output\n", argv[2]);
+               return 1;
+       }
+
+       OurDecoder decoder(fout);
+
+       if(!decoder) {
+               fprintf(stderr, "ERROR: allocating decoder\n");
+               fclose(fout);
+               return 1;
+       }
+
+       (void)decoder.set_md5_checking(true);
+
+       FLAC__StreamDecoderInitStatus init_status = decoder.init(argv[1]);
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
+               ok = false;
+       }
+
+       if(ok) {
+               ok = decoder.process_until_end_of_stream();
+               fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED");
+               fprintf(stderr, "   state: %s\n", decoder.get_state().resolved_as_cstring(decoder));
+       }
+
+       fclose(fout);
+
+       return 0;
+}
+
+::FLAC__StreamDecoderWriteStatus OurDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8));
+       size_t i;
+
+       if(total_samples == 0) {
+               fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+       if(channels != 2 || bps != 16) {
+               fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+
+       /* write WAVE header before we write the first frame */
+       if(frame->header.number.sample_number == 0) {
+               if(
+                       fwrite("RIFF", 1, 4, f) < 4 ||
+                       !write_little_endian_uint32(f, total_size + 36) ||
+                       fwrite("WAVEfmt ", 1, 8, f) < 8 ||
+                       !write_little_endian_uint32(f, 16) ||
+                       !write_little_endian_uint16(f, 1) ||
+                       !write_little_endian_uint16(f, (FLAC__uint16)channels) ||
+                       !write_little_endian_uint32(f, sample_rate) ||
+                       !write_little_endian_uint32(f, sample_rate * channels * (bps/8)) ||
+                       !write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */
+                       !write_little_endian_uint16(f, (FLAC__uint16)bps) ||
+                       fwrite("data", 1, 4, f) < 4 ||
+                       !write_little_endian_uint32(f, total_size)
+               ) {
+                       fprintf(stderr, "ERROR: write error\n");
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+
+       /* write decoded PCM samples */
+       for(i = 0; i < frame->header.blocksize; i++) {
+               if(
+                       !write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) ||  /* left channel */
+                       !write_little_endian_int16(f, (FLAC__int16)buffer[1][i])     /* right channel */
+               ) {
+                       fprintf(stderr, "ERROR: write error\n");
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void OurDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+       /* print some stats */
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               /* save for later */
+               total_samples = metadata->data.stream_info.total_samples;
+               sample_rate = metadata->data.stream_info.sample_rate;
+               channels = metadata->data.stream_info.channels;
+               bps = metadata->data.stream_info.bits_per_sample;
+
+               fprintf(stderr, "sample rate    : %u Hz\n", sample_rate);
+               fprintf(stderr, "channels       : %u\n", channels);
+               fprintf(stderr, "bits per sample: %u\n", bps);
+#ifdef _MSC_VER
+               fprintf(stderr, "total samples  : %I64u\n", total_samples);
+#else
+               fprintf(stderr, "total samples  : %llu\n", total_samples);
+#endif
+       }
+}
+
+void OurDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
diff --git a/examples/cpp/encode/Makefile.am b/examples/cpp/encode/Makefile.am
new file mode 100644 (file)
index 0000000..35bb987
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = file
diff --git a/examples/cpp/encode/file/Makefile.am b/examples/cpp/encode/file/Makefile.am
new file mode 100644 (file)
index 0000000..4a0a8af
--- /dev/null
@@ -0,0 +1,30 @@
+#  example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       example_cpp_encode_file.dsp \
+       example_cpp_encode_file.vcproj
+
+noinst_PROGRAMS = example_cpp_encode_file
+example_cpp_encode_file_LDADD = \
+       $(top_builddir)/src/libFLAC++/libFLAC++.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+example_cpp_encode_file_SOURCES = main.cpp
diff --git a/examples/cpp/encode/file/Makefile.lite b/examples/cpp/encode/file/Makefile.lite
new file mode 100644 (file)
index 0000000..9ae1b12
--- /dev/null
@@ -0,0 +1,41 @@
+#  example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+#  Copyright (C) 2007  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
+#
+
+topdir = ../../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = example_cpp_encode_file
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lFLAC++ -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_CPP = main.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/examples/cpp/encode/file/example_cpp_encode_file.dsp b/examples/cpp/encode/file/example_cpp_encode_file.dsp
new file mode 100644 (file)
index 0000000..cf15030
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="example_cpp_encode_file" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=example_cpp_encode_file - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_cpp_encode_file.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "example_cpp_encode_file.mak" CFG="example_cpp_encode_file - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "example_cpp_encode_file - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "example_cpp_encode_file - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "example_cpp_encode_file - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\..\obj\release\lib\libFLAC++_static.lib ..\..\..\..\obj\release\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "example_cpp_encode_file - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\..\obj\debug\lib\libFLAC++_static.lib ..\..\..\..\obj\debug\lib\libFLAC_static.lib ..\..\..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "example_cpp_encode_file - Win32 Release"\r
+# Name "example_cpp_encode_file - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/examples/cpp/encode/file/example_cpp_encode_file.vcproj b/examples/cpp/encode/file/example_cpp_encode_file.vcproj
new file mode 100644 (file)
index 0000000..72117f1
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="example_cpp_encode_file"\r
+       ProjectGUID="{4cefbe01-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="example_cpp_encode_file"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories="..\..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93292580-829B-b441-E8B8-65A95828BEB0}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{9C7247F1-CA27-1761-A016-0F27452AD2F0}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/examples/cpp/encode/file/main.cpp b/examples/cpp/encode/file/main.cpp
new file mode 100644 (file)
index 0000000..22448bb
--- /dev/null
@@ -0,0 +1,175 @@
+/* example_cpp_encode_file - Simple FLAC file encoder using libFLAC
+ * Copyright (C) 2007  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.
+ */
+
+/*
+ * This example shows how to use libFLAC++ to encode a WAVE file to a FLAC
+ * file.  It only supports 16-bit stereo files in canonical WAVE format.
+ *
+ * Complete API documentation can be found at:
+ *   http://flac.sourceforge.net/api/
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "FLAC++/metadata.h"
+#include "FLAC++/encoder.h"
+
+class OurEncoder: public FLAC::Encoder::File {
+public:
+       OurEncoder(): FLAC::Encoder::File() { }
+protected:
+       virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
+};
+
+#define READSIZE 1024
+
+static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
+static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
+static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
+static FLAC__int32 *pcm_[2] = { pcm, pcm+READSIZE };
+
+int main(int argc, char *argv[])
+{
+       bool ok = true;
+       OurEncoder encoder;
+       FLAC__StreamEncoderInitStatus init_status;
+       FLAC__StreamMetadata *metadata[2];
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+       FILE *fin;
+       unsigned sample_rate = 0;
+       unsigned channels = 0;
+       unsigned bps = 0;
+
+       if(argc != 3) {
+               fprintf(stderr, "usage: %s infile.wav outfile.flac\n", argv[0]);
+               return 1;
+       }
+
+       if((fin = fopen(argv[1], "rb")) == NULL) {
+               fprintf(stderr, "ERROR: opening %s for output\n", argv[1]);
+               return 1;
+       }
+
+       /* read wav header and validate it */
+       if(
+               fread(buffer, 1, 44, fin) != 44 ||
+               memcmp(buffer, "RIFF", 4) ||
+               memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
+               memcmp(buffer+32, "\004\000\020\000data", 8)
+       ) {
+               fprintf(stderr, "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n");
+               fclose(fin);
+               return 1;
+       }
+       sample_rate = ((((((unsigned)buffer[27] << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24];
+       channels = 2;
+       bps = 16;
+       total_samples = (((((((unsigned)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
+   
+       /* check the encoder */
+       if(!encoder) {
+               fprintf(stderr, "ERROR: allocating encoder\n");
+               fclose(fin);
+               return 1;
+       }
+
+       ok &= encoder.set_verify(true);
+       ok &= encoder.set_compression_level(5);
+       ok &= encoder.set_channels(channels);
+       ok &= encoder.set_bits_per_sample(bps);
+       ok &= encoder.set_sample_rate(sample_rate);
+       ok &= encoder.set_total_samples_estimate(total_samples);
+
+       /* now add some metadata; we'll add some tags and a padding block */
+       if(ok) {
+               if(
+                       (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
+                       (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
+                       /* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
+                       !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") ||
+                       !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */
+                       !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") ||
+                       !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false)
+               ) {
+                       fprintf(stderr, "ERROR: out of memory or tag error\n");
+                       ok = false;
+               }
+
+               metadata[1]->length = 1234; /* set the padding length */
+
+               ok = encoder.set_metadata(metadata, 2);
+       }
+
+       /* initialize encoder */
+       if(ok) {
+               init_status = encoder.init(argv[2]);
+               if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+                       fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
+                       ok = false;
+               }
+       }
+
+       /* read blocks of samples from WAVE file and feed to encoder */
+       if(ok) {
+               size_t left = (size_t)total_samples;
+               while(ok && left) {
+                       size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
+                       if(fread(buffer, channels*(bps/8), need, fin) != need) {
+                               fprintf(stderr, "ERROR: reading from WAVE file\n");
+                               ok = false;
+                       }
+                       else {
+                               /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
+                               size_t i;
+                               for(i = 0; i < need*channels; i++) {
+                                       /* inefficient but simple and works on big- or little-endian machines */
+                                       pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
+                               }
+                               /* feed samples to encoder */
+                               ok = encoder.process_interleaved(pcm, need);
+                       }
+                       left -= need;
+               }
+       }
+
+       ok &= encoder.finish();
+
+       fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED");
+       fprintf(stderr, "   state: %s\n", encoder.get_state().resolved_as_cstring(encoder));
+
+       /* now that encoding is finished, the metadata can be freed */
+       FLAC__metadata_object_delete(metadata[0]);
+       FLAC__metadata_object_delete(metadata[1]);
+
+       fclose(fin);
+
+       return 0;
+}
+
+void OurEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
+{
+#ifdef _MSC_VER
+       fprintf(stderr, "wrote %I64u bytes, %I64u/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+#else
+       fprintf(stderr, "wrote %llu bytes, %llu/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
+#endif
+}
diff --git a/examples/examples.dsp b/examples/examples.dsp
new file mode 100644 (file)
index 0000000..a608a67
--- /dev/null
@@ -0,0 +1,67 @@
+# Microsoft Developer Studio Project File - Name="examples" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a\r
+\r
+CFG=examples - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "examples.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "examples.mak" CFG="examples - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "examples - Win32 Release" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE "examples - Win32 Debug" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "all"\r
+# PROP Scc_LocalPath "."\r
+MTL=midl.exe\r
+\r
+!IF  "$(CFG)" == "examples - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\obj\release"\r
+# PROP Intermediate_Dir "..\obj\release"\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "examples - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\obj\debug"\r
+# PROP Intermediate_Dir "..\obj\debug"\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "examples - Win32 Release"\r
+# Name "examples - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\README\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/include/FLAC++/Makefile.am b/include/FLAC++/Makefile.am
new file mode 100644 (file)
index 0000000..e833c8a
--- /dev/null
@@ -0,0 +1,38 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+flaccppincludedir = $(includedir)/FLAC++
+
+flaccppinclude_HEADERS = \
+       all.h \
+       decoder.h \
+       encoder.h \
+       export.h \
+       metadata.h
diff --git a/include/FLAC++/all.h b/include/FLAC++/all.h
new file mode 100644 (file)
index 0000000..140470d
--- /dev/null
@@ -0,0 +1,48 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLACPP__ALL_H
+#define FLACPP__ALL_H
+
+#include "export.h"
+
+#include "encoder.h"
+#include "decoder.h"
+#include "metadata.h"
+
+/** \defgroup flacpp FLAC C++ API
+ *
+ * The FLAC C++ API is the interface to libFLAC++, a set of classes
+ * that encapsulate the encoders, decoders, and metadata interfaces
+ * in libFLAC.
+ */
+
+#endif
diff --git a/include/FLAC++/decoder.h b/include/FLAC++/decoder.h
new file mode 100644 (file)
index 0000000..719f66c
--- /dev/null
@@ -0,0 +1,245 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLACPP__DECODER_H
+#define FLACPP__DECODER_H
+
+#include "export.h"
+
+#include <string>
+#include "FLAC/stream_decoder.h"
+
+
+/** \file include/FLAC++/decoder.h
+ *
+ *  \brief
+ *  This module contains the classes which implement the various
+ *  decoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_decoder decoder \endlink module.
+ */
+
+/** \defgroup flacpp_decoder FLAC++/decoder.h: decoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module describes the decoder layers provided by libFLAC++.
+ *
+ * The libFLAC++ decoder classes are object wrappers around their
+ * counterparts in libFLAC.  All decoding layers available in
+ * libFLAC are also provided here.  The interface is very similar;
+ * make sure to read the \link flac_decoder libFLAC decoder module \endlink.
+ *
+ * There are only two significant differences here.  First, instead of
+ * passing in C function pointers for callbacks, you inherit from the
+ * decoder class and provide implementations for the callbacks in your
+ * derived class; because of this there is no need for a 'client_data'
+ * property.
+ *
+ * Second, there are two stream decoder classes.  FLAC::Decoder::Stream
+ * is used for the same cases that FLAC__stream_decoder_init_stream() /
+ * FLAC__stream_decoder_init_ogg_stream() are used, and FLAC::Decoder::File
+ * is used for the same cases that
+ * FLAC__stream_decoder_init_FILE() and FLAC__stream_decoder_init_file() /
+ * FLAC__stream_decoder_init_ogg_FILE() and FLAC__stream_decoder_init_ogg_file()
+ * are used.
+ */
+
+namespace FLAC {
+       namespace Decoder {
+
+               /** \ingroup flacpp_decoder
+                *  \brief
+                *  This class wraps the ::FLAC__StreamDecoder.  If you are
+                *  decoding from a file, FLAC::Decoder::File may be more
+                *  convenient.
+                *
+                * The usage of this class is similar to FLAC__StreamDecoder,
+                * except instead of providing callbacks to
+                * FLAC__stream_decoder_init*_stream(), you will inherit from this
+                * class and override the virtual callback functions with your
+                * own implementations, then call init() or init_ogg().  The rest
+                * of the calls work the same as in the C layer.
+                *
+                * Only the read, write, and error callbacks are mandatory.  The
+                * others are optional; this class provides default
+                * implementations that do nothing.  In order for seeking to work
+                * you must overide seek_callback(), tell_callback(),
+                * length_callback(), and eof_callback().
+                */
+               class FLACPP_API Stream {
+               public:
+                       /** This class is a wrapper around FLAC__StreamDecoderState.
+                        */
+                       class FLACPP_API State {
+                       public:
+                               inline State(::FLAC__StreamDecoderState state): state_(state) { }
+                               inline operator ::FLAC__StreamDecoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::FLAC__StreamDecoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const Stream &decoder) const { return ::FLAC__stream_decoder_get_resolved_state_string(decoder.decoder_); }
+                       protected:
+                               ::FLAC__StreamDecoderState state_;
+                       };
+
+                       Stream();
+                       virtual ~Stream();
+
+                       //@{
+                       /** Call after construction to check the that the object was created
+                        *  successfully.  If not, use get_state() to find out why not.
+                        */
+                       virtual bool is_valid() const;
+                       inline operator bool() const { return is_valid(); } ///< See is_valid()
+                       //@}
+
+                       virtual bool set_ogg_serial_number(long value);                        ///< See FLAC__stream_decoder_set_ogg_serial_number()
+                       virtual bool set_md5_checking(bool value);                             ///< See FLAC__stream_decoder_set_md5_checking()
+                       virtual bool set_metadata_respond(::FLAC__MetadataType type);          ///< See FLAC__stream_decoder_set_metadata_respond()
+                       virtual bool set_metadata_respond_application(const FLAC__byte id[4]); ///< See FLAC__stream_decoder_set_metadata_respond_application()
+                       virtual bool set_metadata_respond_all();                               ///< See FLAC__stream_decoder_set_metadata_respond_all()
+                       virtual bool set_metadata_ignore(::FLAC__MetadataType type);           ///< See FLAC__stream_decoder_set_metadata_ignore()
+                       virtual bool set_metadata_ignore_application(const FLAC__byte id[4]);  ///< See FLAC__stream_decoder_set_metadata_ignore_application()
+                       virtual bool set_metadata_ignore_all();                                ///< See FLAC__stream_decoder_set_metadata_ignore_all()
+
+                       /* get_state() is not virtual since we want subclasses to be able to return their own state */
+                       State get_state() const;                                          ///< See FLAC__stream_decoder_get_state()
+                       virtual bool get_md5_checking() const;                            ///< See FLAC__stream_decoder_get_md5_checking()
+                       virtual FLAC__uint64 get_total_samples() const;                   ///< See FLAC__stream_decoder_get_total_samples()
+                       virtual unsigned get_channels() const;                            ///< See FLAC__stream_decoder_get_channels()
+                       virtual ::FLAC__ChannelAssignment get_channel_assignment() const; ///< See FLAC__stream_decoder_get_channel_assignment()
+                       virtual unsigned get_bits_per_sample() const;                     ///< See FLAC__stream_decoder_get_bits_per_sample()
+                       virtual unsigned get_sample_rate() const;                         ///< See FLAC__stream_decoder_get_sample_rate()
+                       virtual unsigned get_blocksize() const;                           ///< See FLAC__stream_decoder_get_blocksize()
+                       virtual bool get_decode_position(FLAC__uint64 *position) const;   ///< See FLAC__stream_decoder_get_decode_position()
+
+                       virtual ::FLAC__StreamDecoderInitStatus init();      ///< Seek FLAC__stream_decoder_init_stream()
+                       virtual ::FLAC__StreamDecoderInitStatus init_ogg();  ///< Seek FLAC__stream_decoder_init_ogg_stream()
+
+                       virtual bool finish(); ///< See FLAC__stream_decoder_finish()
+
+                       virtual bool flush(); ///< See FLAC__stream_decoder_flush()
+                       virtual bool reset(); ///< See FLAC__stream_decoder_reset()
+
+                       virtual bool process_single();                ///< See FLAC__stream_decoder_process_single()
+                       virtual bool process_until_end_of_metadata(); ///< See FLAC__stream_decoder_process_until_end_of_metadata()
+                       virtual bool process_until_end_of_stream();   ///< See FLAC__stream_decoder_process_until_end_of_stream()
+                       virtual bool skip_single_frame();             ///< See FLAC__stream_decoder_skip_single_frame()
+
+                       virtual bool seek_absolute(FLAC__uint64 sample); ///< See FLAC__stream_decoder_seek_absolute()
+               protected:
+                       /// see FLAC__StreamDecoderReadCallback
+                       virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) = 0;
+
+                       /// see FLAC__StreamDecoderSeekCallback
+                       virtual ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+
+                       /// see FLAC__StreamDecoderTellCallback
+                       virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+
+                       /// see FLAC__StreamDecoderLengthCallback
+                       virtual ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length);
+
+                       /// see FLAC__StreamDecoderEofCallback
+                       virtual bool eof_callback();
+
+                       /// see FLAC__StreamDecoderWriteCallback
+                       virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
+
+                       /// see FLAC__StreamDecoderMetadataCallback
+                       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+
+                       /// see FLAC__StreamDecoderErrorCallback
+                       virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0;
+
+#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
+                       // lame hack: some MSVC/GCC versions can't see a protected decoder_ from nested State::resolved_as_cstring()
+                       friend State;
+#endif
+                       ::FLAC__StreamDecoder *decoder_;
+
+                       static ::FLAC__StreamDecoderReadStatus read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+                       static ::FLAC__StreamDecoderSeekStatus seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+                       static ::FLAC__StreamDecoderTellStatus tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+                       static ::FLAC__StreamDecoderLengthStatus length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+                       static FLAC__bool eof_callback_(const ::FLAC__StreamDecoder *decoder, 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);
+               private:
+                       // Private and undefined so you can't use them:
+                       Stream(const Stream &);
+                       void operator=(const Stream &);
+               };
+
+               /** \ingroup flacpp_decoder
+                *  \brief
+                *  This class wraps the ::FLAC__StreamDecoder.  If you are
+                *  not decoding from a file, you may need to use
+                *  FLAC::Decoder::Stream.
+                *
+                * The usage of this class is similar to FLAC__StreamDecoder,
+                * except instead of providing callbacks to
+                * FLAC__stream_decoder_init*_FILE() or
+                * FLAC__stream_decoder_init*_file(), you will inherit from this
+                * class and override the virtual callback functions with your
+                * own implementations, then call init() or init_off().  The rest
+                * of the calls work the same as in the C layer.
+                *
+                * Only the write, and error callbacks from FLAC::Decoder::Stream
+                * are mandatory.  The others are optional; this class provides
+                * full working implementations for all other callbacks and
+                * supports seeking.
+                */
+               class FLACPP_API File: public Stream {
+               public:
+                       File();
+                       virtual ~File();
+
+                       virtual ::FLAC__StreamDecoderInitStatus init(FILE *file);                      ///< See FLAC__stream_decoder_init_FILE()
+                       virtual ::FLAC__StreamDecoderInitStatus init(const char *filename);            ///< See FLAC__stream_decoder_init_file()
+                       virtual ::FLAC__StreamDecoderInitStatus init(const std::string &filename);     ///< See FLAC__stream_decoder_init_file()
+                       virtual ::FLAC__StreamDecoderInitStatus init_ogg(FILE *file);                  ///< See FLAC__stream_decoder_init_ogg_FILE()
+                       virtual ::FLAC__StreamDecoderInitStatus init_ogg(const char *filename);        ///< See FLAC__stream_decoder_init_ogg_file()
+                       virtual ::FLAC__StreamDecoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_decoder_init_ogg_file()
+               protected:
+                       // this is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer
+                       virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+               private:
+                       // Private and undefined so you can't use them:
+                       File(const File &);
+                       void operator=(const File &);
+               };
+
+       }
+}
+
+#endif
diff --git a/include/FLAC++/encoder.h b/include/FLAC++/encoder.h
new file mode 100644 (file)
index 0000000..b944e99
--- /dev/null
@@ -0,0 +1,260 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLACPP__ENCODER_H
+#define FLACPP__ENCODER_H
+
+#include "export.h"
+
+#include "FLAC/stream_encoder.h"
+#include "decoder.h"
+#include "metadata.h"
+
+
+/** \file include/FLAC++/encoder.h
+ *
+ *  \brief
+ *  This module contains the classes which implement the various
+ *  encoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_encoder encoder \endlink module.
+ */
+
+/** \defgroup flacpp_encoder FLAC++/encoder.h: encoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module describes the encoder layers provided by libFLAC++.
+ *
+ * The libFLAC++ encoder classes are object wrappers around their
+ * counterparts in libFLAC.  All encoding layers available in
+ * libFLAC are also provided here.  The interface is very similar;
+ * make sure to read the \link flac_encoder libFLAC encoder module \endlink.
+ *
+ * There are only two significant differences here.  First, instead of
+ * passing in C function pointers for callbacks, you inherit from the
+ * encoder class and provide implementations for the callbacks in your
+ * derived class; because of this there is no need for a 'client_data'
+ * property.
+ *
+ * Second, there are two stream encoder classes.  FLAC::Encoder::Stream
+ * is used for the same cases that FLAC__stream_encoder_init_stream() /
+ * FLAC__stream_encoder_init_ogg_stream() are used, and FLAC::Encoder::File
+ * is used for the same cases that
+ * FLAC__stream_encoder_init_FILE() and FLAC__stream_encoder_init_file() /
+ * FLAC__stream_encoder_init_ogg_FILE() and FLAC__stream_encoder_init_ogg_file()
+ * are used.
+ */
+
+namespace FLAC {
+       namespace Encoder {
+
+               /** \ingroup flacpp_encoder
+                *  \brief
+                *  This class wraps the ::FLAC__StreamEncoder.  If you are
+                *  encoding to a file, FLAC::Encoder::File may be more
+                *  convenient.
+                *
+                * The usage of this class is similar to FLAC__StreamEncoder,
+                * except instead of providing callbacks to
+                * FLAC__stream_encoder_init*_stream(), you will inherit from this
+                * class and override the virtual callback functions with your
+                * own implementations, then call init() or init_ogg().  The rest of
+                * the calls work the same as in the C layer.
+                *
+                * Only the write callback is mandatory.  The others are
+                * optional; this class provides default implementations that do
+                * nothing.  In order for some STREAMINFO and SEEKTABLE data to
+                * be written properly, you must overide seek_callback() and
+                * tell_callback(); see FLAC__stream_encoder_init_stream() as to
+                * why.
+                */
+               class FLACPP_API Stream {
+               public:
+                       /** This class is a wrapper around FLAC__StreamEncoderState.
+                        */
+                       class FLACPP_API State {
+                       public:
+                               inline State(::FLAC__StreamEncoderState state): state_(state) { }
+                               inline operator ::FLAC__StreamEncoderState() const { return state_; }
+                               inline const char *as_cstring() const { return ::FLAC__StreamEncoderStateString[state_]; }
+                               inline const char *resolved_as_cstring(const Stream &encoder) const { return ::FLAC__stream_encoder_get_resolved_state_string(encoder.encoder_); }
+                       protected:
+                               ::FLAC__StreamEncoderState state_;
+                       };
+
+                       Stream();
+                       virtual ~Stream();
+
+                       //@{
+                       /** Call after construction to check the that the object was created
+                        *  successfully.  If not, use get_state() to find out why not.
+                        *
+                        */
+                       virtual bool is_valid() const;
+                       inline operator bool() const { return is_valid(); } ///< See is_valid()
+                       //@}
+
+                       virtual bool set_ogg_serial_number(long value);                 ///< See FLAC__stream_encoder_set_ogg_serial_number()
+                       virtual bool set_verify(bool value);                            ///< See FLAC__stream_encoder_set_verify()
+                       virtual bool set_streamable_subset(bool value);                 ///< See FLAC__stream_encoder_set_streamable_subset()
+                       virtual bool set_channels(unsigned value);                      ///< See FLAC__stream_encoder_set_channels()
+                       virtual bool set_bits_per_sample(unsigned value);               ///< See FLAC__stream_encoder_set_bits_per_sample()
+                       virtual bool set_sample_rate(unsigned value);                   ///< See FLAC__stream_encoder_set_sample_rate()
+                       virtual bool set_compression_level(unsigned value);             ///< See FLAC__stream_encoder_set_compression_level()
+                       virtual bool set_blocksize(unsigned value);                     ///< See FLAC__stream_encoder_set_blocksize()
+                       virtual bool set_do_mid_side_stereo(bool value);                ///< See FLAC__stream_encoder_set_do_mid_side_stereo()
+                       virtual bool set_loose_mid_side_stereo(bool value);             ///< See FLAC__stream_encoder_set_loose_mid_side_stereo()
+                       virtual bool set_apodization(const char *specification);        ///< See FLAC__stream_encoder_set_apodization()
+                       virtual bool set_max_lpc_order(unsigned value);                 ///< See FLAC__stream_encoder_set_max_lpc_order()
+                       virtual bool set_qlp_coeff_precision(unsigned value);           ///< See FLAC__stream_encoder_set_qlp_coeff_precision()
+                       virtual bool set_do_qlp_coeff_prec_search(bool value);          ///< See FLAC__stream_encoder_set_do_qlp_coeff_prec_search()
+                       virtual bool set_do_escape_coding(bool value);                  ///< See FLAC__stream_encoder_set_do_escape_coding()
+                       virtual bool set_do_exhaustive_model_search(bool value);        ///< See FLAC__stream_encoder_set_do_exhaustive_model_search()
+                       virtual bool set_min_residual_partition_order(unsigned value);  ///< See FLAC__stream_encoder_set_min_residual_partition_order()
+                       virtual bool set_max_residual_partition_order(unsigned value);  ///< See FLAC__stream_encoder_set_max_residual_partition_order()
+                       virtual bool set_rice_parameter_search_dist(unsigned value);    ///< See FLAC__stream_encoder_set_rice_parameter_search_dist()
+                       virtual bool set_total_samples_estimate(FLAC__uint64 value);    ///< See FLAC__stream_encoder_set_total_samples_estimate()
+                       virtual bool set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks);    ///< See FLAC__stream_encoder_set_metadata()
+                       virtual bool set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks); ///< See FLAC__stream_encoder_set_metadata()
+
+                       /* get_state() is not virtual since we want subclasses to be able to return their own state */
+                       State get_state() const;                                   ///< See FLAC__stream_encoder_get_state()
+                       virtual Decoder::Stream::State get_verify_decoder_state() const; ///< See FLAC__stream_encoder_get_verify_decoder_state()
+                       virtual void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got); ///< See FLAC__stream_encoder_get_verify_decoder_error_stats()
+                       virtual bool     get_verify() const;                       ///< See FLAC__stream_encoder_get_verify()
+                       virtual bool     get_streamable_subset() const;            ///< See FLAC__stream_encoder_get_streamable_subset()
+                       virtual bool     get_do_mid_side_stereo() const;           ///< See FLAC__stream_encoder_get_do_mid_side_stereo()
+                       virtual bool     get_loose_mid_side_stereo() const;        ///< See FLAC__stream_encoder_get_loose_mid_side_stereo()
+                       virtual unsigned get_channels() const;                     ///< See FLAC__stream_encoder_get_channels()
+                       virtual unsigned get_bits_per_sample() const;              ///< See FLAC__stream_encoder_get_bits_per_sample()
+                       virtual unsigned get_sample_rate() const;                  ///< See FLAC__stream_encoder_get_sample_rate()
+                       virtual unsigned get_blocksize() const;                    ///< See FLAC__stream_encoder_get_blocksize()
+                       virtual unsigned get_max_lpc_order() const;                ///< See FLAC__stream_encoder_get_max_lpc_order()
+                       virtual unsigned get_qlp_coeff_precision() const;          ///< See FLAC__stream_encoder_get_qlp_coeff_precision()
+                       virtual bool     get_do_qlp_coeff_prec_search() const;     ///< See FLAC__stream_encoder_get_do_qlp_coeff_prec_search()
+                       virtual bool     get_do_escape_coding() const;             ///< See FLAC__stream_encoder_get_do_escape_coding()
+                       virtual bool     get_do_exhaustive_model_search() const;   ///< See FLAC__stream_encoder_get_do_exhaustive_model_search()
+                       virtual unsigned get_min_residual_partition_order() const; ///< See FLAC__stream_encoder_get_min_residual_partition_order()
+                       virtual unsigned get_max_residual_partition_order() const; ///< See FLAC__stream_encoder_get_max_residual_partition_order()
+                       virtual unsigned get_rice_parameter_search_dist() const;   ///< See FLAC__stream_encoder_get_rice_parameter_search_dist()
+                       virtual FLAC__uint64 get_total_samples_estimate() const;   ///< See FLAC__stream_encoder_get_total_samples_estimate()
+
+                       virtual ::FLAC__StreamEncoderInitStatus init();            ///< See FLAC__stream_encoder_init_stream()
+                       virtual ::FLAC__StreamEncoderInitStatus init_ogg();        ///< See FLAC__stream_encoder_init_ogg_stream()
+
+                       virtual bool finish(); ///< See FLAC__stream_encoder_finish()
+
+                       virtual bool process(const FLAC__int32 * const buffer[], unsigned samples);     ///< See FLAC__stream_encoder_process()
+                       virtual bool process_interleaved(const FLAC__int32 buffer[], unsigned samples); ///< See FLAC__stream_encoder_process_interleaved()
+               protected:
+                       /// See FLAC__StreamEncoderReadCallback
+                       virtual ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+
+                       /// See FLAC__StreamEncoderWriteCallback
+                       virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame) = 0;
+
+                       /// See FLAC__StreamEncoderSeekCallback
+                       virtual ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+
+                       /// See FLAC__StreamEncoderTellCallback
+                       virtual ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+
+                       /// See FLAC__StreamEncoderMetadataCallback
+                       virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+
+#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
+                       // lame hack: some MSVC/GCC versions can't see a protected encoder_ from nested State::resolved_as_cstring()
+                       friend State;
+#endif
+                       ::FLAC__StreamEncoder *encoder_;
+
+                       static ::FLAC__StreamEncoderReadStatus read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+                       static ::FLAC__StreamEncoderWriteStatus write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+                       static ::FLAC__StreamEncoderSeekStatus seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+                       static ::FLAC__StreamEncoderTellStatus tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+                       static void metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+               private:
+                       // Private and undefined so you can't use them:
+                       Stream(const Stream &);
+                       void operator=(const Stream &);
+               };
+
+               /** \ingroup flacpp_encoder
+                *  \brief
+                *  This class wraps the ::FLAC__StreamEncoder.  If you are
+                *  not encoding to a file, you may need to use
+                *  FLAC::Encoder::Stream.
+                *
+                * The usage of this class is similar to FLAC__StreamEncoder,
+                * except instead of providing callbacks to
+                * FLAC__stream_encoder_init*_FILE() or
+                * FLAC__stream_encoder_init*_file(), you will inherit from this
+                * class and override the virtual callback functions with your
+                * own implementations, then call init() or init_ogg().  The rest
+                * of the calls work the same as in the C layer.
+                *
+                * There are no mandatory callbacks; all the callbacks from
+                * FLAC::Encoder::Stream are implemented here fully and support
+                * full post-encode STREAMINFO and SEEKTABLE updating.  There is
+                * only an optional progress callback which you may override to
+                * get periodic reports on the progress of the encode.
+                */
+               class FLACPP_API File: public Stream {
+               public:
+                       File();
+                       virtual ~File();
+
+                       virtual ::FLAC__StreamEncoderInitStatus init(FILE *file);                      ///< See FLAC__stream_encoder_init_FILE()
+                       virtual ::FLAC__StreamEncoderInitStatus init(const char *filename);            ///< See FLAC__stream_encoder_init_file()
+                       virtual ::FLAC__StreamEncoderInitStatus init(const std::string &filename);     ///< See FLAC__stream_encoder_init_file()
+                       virtual ::FLAC__StreamEncoderInitStatus init_ogg(FILE *file);                  ///< See FLAC__stream_encoder_init_ogg_FILE()
+                       virtual ::FLAC__StreamEncoderInitStatus init_ogg(const char *filename);        ///< See FLAC__stream_encoder_init_ogg_file()
+                       virtual ::FLAC__StreamEncoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_encoder_init_ogg_file()
+               protected:
+                       /// See FLAC__StreamEncoderProgressCallback
+                       virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
+
+                       /// This is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer
+                       virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame);
+               private:
+                       static void progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+                       // Private and undefined so you can't use them:
+                       File(const Stream &);
+                       void operator=(const Stream &);
+               };
+
+       }
+}
+
+#endif
diff --git a/include/FLAC++/export.h b/include/FLAC++/export.h
new file mode 100644 (file)
index 0000000..d2deb7b
--- /dev/null
@@ -0,0 +1,80 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLACPP__EXPORT_H
+#define FLACPP__EXPORT_H
+
+/** \file include/FLAC++/export.h
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  See the \link flacpp_export export \endlink module.
+ */
+
+/** \defgroup flacpp_export FLAC++/export.h: export symbols
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  If you are compiling with MSVC and will link to the static library
+ *  (libFLAC++.lib) you should define FLAC__NO_DLL in your project to
+ *  make sure the symbols are exported properly.
+ *
+ * \{
+ */
+
+#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
+#define FLACPP_API
+
+#else
+
+#ifdef FLACPP_API_EXPORTS
+#define        FLACPP_API      _declspec(dllexport)
+#else
+#define FLACPP_API     _declspec(dllimport)
+
+#endif
+#endif
+
+/* These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual.html#Libtool-versioning
+ */
+#define FLACPP_API_VERSION_CURRENT 8
+#define FLACPP_API_VERSION_REVISION 0
+#define FLACPP_API_VERSION_AGE 2
+
+/* \} */
+
+#endif
diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h
new file mode 100644 (file)
index 0000000..8c6a015
--- /dev/null
@@ -0,0 +1,1156 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLACPP__METADATA_H
+#define FLACPP__METADATA_H
+
+#include "export.h"
+
+#include "FLAC/metadata.h"
+
+// ===============================================================
+//
+//  Full documentation for the metadata interface can be found
+//  in the C layer in include/FLAC/metadata.h
+//
+// ===============================================================
+
+/** \file include/FLAC++/metadata.h
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flacpp_metadata metadata \endlink module.
+ */
+
+/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  The behavior closely mimics the C layer interface; be sure to read
+ *  the detailed description of the
+ *  \link flac_metadata C metadata module \endlink.  Note that like the
+ *  C layer, currently only the Chain interface (level 2) supports Ogg
+ *  FLAC files, and it is read-only i.e. no writing back changed
+ *  metadata to file.
+ */
+
+
+namespace FLAC {
+       namespace Metadata {
+
+               // ============================================================
+               //
+               //  Metadata objects
+               //
+               // ============================================================
+
+               /** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes
+                *  \ingroup flacpp_metadata
+                *
+                * This module contains classes representing FLAC metadata
+                * blocks in memory.
+                *
+                * The behavior closely mimics the C layer interface; be
+                * sure to read the detailed description of the
+                * \link flac_metadata_object C metadata object module \endlink.
+                *
+                * Any time a metadata object is constructed or assigned, you
+                * should check is_valid() to make sure the underlying
+                * ::FLAC__StreamMetadata object was able to be created.
+                *
+                * \warning
+                * When the get_*() methods of any metadata object method
+                * return you a const pointer, DO NOT disobey and write into it.
+                * Always use the set_*() methods.
+                *
+                * \{
+                */
+
+               /** Base class for all metadata block types.
+                *  See the \link flacpp_metadata_object overview \endlink for more.
+                */
+               class FLACPP_API Prototype {
+               protected:
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       Prototype(const Prototype &);
+                       Prototype(const ::FLAC__StreamMetadata &);
+                       Prototype(const ::FLAC__StreamMetadata *);
+                       //@}
+
+                       /** Constructs an object with copy control.  When \a copy
+                        *  is \c true, behaves identically to
+                        *  FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object).
+                        *  When \a copy is \c false, the instance takes ownership of
+                        *  the pointer and the ::FLAC__StreamMetadata object will
+                        *  be freed by the destructor.
+                        *
+                        *  \assert
+                        *    \code object != NULL \endcode
+                        */
+                       Prototype(::FLAC__StreamMetadata *object, bool copy);
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       Prototype &operator=(const Prototype &);
+                       Prototype &operator=(const ::FLAC__StreamMetadata &);
+                       Prototype &operator=(const ::FLAC__StreamMetadata *);
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       Prototype &assign_object(::FLAC__StreamMetadata *object, bool copy);
+
+                       /** Deletes the underlying ::FLAC__StreamMetadata object.
+                        */
+                       virtual void clear();
+
+                       ::FLAC__StreamMetadata *object_;
+               public:
+                       /** Deletes the underlying ::FLAC__StreamMetadata object.
+                        */
+                       virtual ~Prototype();
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers.
+                        */
+                       inline bool operator==(const Prototype &) const;
+                       inline bool operator==(const ::FLAC__StreamMetadata &) const;
+                       inline bool operator==(const ::FLAC__StreamMetadata *) const;
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       inline bool operator!=(const Prototype &) const;
+                       inline bool operator!=(const ::FLAC__StreamMetadata &) const;
+                       inline bool operator!=(const ::FLAC__StreamMetadata *) const;
+                       //@}
+
+                       friend class SimpleIterator;
+                       friend class Iterator;
+
+                       /** Returns \c true if the object was correctly constructed
+                        *  (i.e. the underlying ::FLAC__StreamMetadata object was
+                        *  properly allocated), else \c false.
+                        */
+                       inline bool is_valid() const;
+
+                       /** Returns \c true if this block is the last block in a
+                        *  stream, else \c false.
+                        *
+                        * \assert
+                        *   \code is_valid() \endcode
+                        */
+                       bool get_is_last() const;
+
+                       /** Returns the type of the block.
+                        *
+                        * \assert
+                        *   \code is_valid() \endcode
+                        */
+                       ::FLAC__MetadataType get_type() const;
+
+                       /** Returns the stream length of the metadata block.
+                        *
+                        * \note
+                        *   The length does not include the metadata block header,
+                        *   per spec.
+                        *
+                        * \assert
+                        *   \code is_valid() \endcode
+                        */
+                       unsigned get_length() const;
+
+                       /** Sets the "is_last" flag for the block.  When using the iterators
+                        *  it is not necessary to set this flag; they will do it for you.
+                        *
+                        * \assert
+                        *   \code is_valid() \endcode
+                        */
+                       void set_is_last(bool);
+
+                       /** Returns a pointer to the underlying ::FLAC__StreamMetadata
+                        *  object.  This can be useful for plugging any holes between
+                        *  the C++ and C interfaces.
+                        *
+                        * \assert
+                        *   \code is_valid() \endcode
+                        */
+                       inline operator const ::FLAC__StreamMetadata *() const;
+               private:
+                       /** Private and undefined so you can't use it. */
+                       Prototype();
+
+                       // These are used only by Iterator
+                       bool is_reference_;
+                       inline void set_reference(bool x) { is_reference_ = x; }
+               };
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+               inline bool Prototype::operator==(const Prototype &object) const
+               { return (bool)::FLAC__metadata_object_is_equal(object_, object.object_); }
+
+               inline bool Prototype::operator==(const ::FLAC__StreamMetadata &object) const
+               { return (bool)::FLAC__metadata_object_is_equal(object_, &object); }
+
+               inline bool Prototype::operator==(const ::FLAC__StreamMetadata *object) const
+               { return (bool)::FLAC__metadata_object_is_equal(object_, object); }
+
+#ifdef _MSC_VER
+// @@@ how to re-enable?  the following doesn't work
+// #pragma warning ( enable : 4800 )
+#endif
+
+               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_; }
+
+               inline Prototype::operator const ::FLAC__StreamMetadata *() const
+               { return object_; }
+
+               /** Create a deep copy of an object and return it. */
+               FLACPP_API Prototype *clone(const Prototype *);
+
+
+               /** STREAMINFO metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_streaminfo">format specification</A>.
+                */
+               class FLACPP_API StreamInfo : public Prototype {
+               public:
+                       StreamInfo();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline StreamInfo(const StreamInfo &object): Prototype(object) { }
+                       inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~StreamInfo();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline StreamInfo &operator=(const StreamInfo &object) { Prototype::operator=(object); return *this; }
+                       inline StreamInfo &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline StreamInfo &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline StreamInfo &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** See <A HREF="../format.html#metadata_block_streaminfo">format specification</A>. */
+                       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]);
+                       //@}
+               };
+
+               /** PADDING metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_padding">format specification</A>.
+                */
+               class FLACPP_API Padding : public Prototype {
+               public:
+                       Padding();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline Padding(const Padding &object): Prototype(object) { }
+                       inline Padding(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline Padding(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Padding(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~Padding();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline Padding &operator=(const Padding &object) { Prototype::operator=(object); return *this; }
+                       inline Padding &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline Padding &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Padding &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       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);
+               };
+
+               /** APPLICATION metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_application">format specification</A>.
+                */
+               class FLACPP_API Application : public Prototype {
+               public:
+                       Application();
+                       //
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline Application(const Application &object): Prototype(object) { }
+                       inline Application(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline Application(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Application(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~Application();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline Application &operator=(const Application &object) { Prototype::operator=(object); return *this; }
+                       inline Application &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline Application &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Application &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       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;
+
+                       void set_id(const FLAC__byte value[4]);
+                       //! This form always copies \a data
+                       bool set_data(const FLAC__byte *data, unsigned length);
+                       bool set_data(FLAC__byte *data, unsigned length, bool copy);
+               };
+
+               /** SEEKTABLE metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_seektable">format specification</A>.
+                */
+               class FLACPP_API SeekTable : public Prototype {
+               public:
+                       SeekTable();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline SeekTable(const SeekTable &object): Prototype(object) { }
+                       inline SeekTable(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline SeekTable(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline SeekTable(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~SeekTable();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline SeekTable &operator=(const SeekTable &object) { Prototype::operator=(object); return *this; }
+                       inline SeekTable &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline SeekTable &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline SeekTable &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       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;
+
+                       //! See FLAC__metadata_object_seektable_set_point()
+                       void set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point);
+
+                       //! See FLAC__metadata_object_seektable_insert_point()
+                       bool insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point);
+
+                       //! See FLAC__metadata_object_seektable_delete_point()
+                       bool delete_point(unsigned index);
+
+                       //! See FLAC__metadata_object_seektable_is_legal()
+                       bool is_legal() const;
+               };
+
+               /** VORBIS_COMMENT metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>.
+                */
+               class FLACPP_API VorbisComment : public Prototype {
+               public:
+                       /** Convenience class for encapsulating Vorbis comment
+                        *  entries.  An entry is a vendor string or a comment
+                        *  field.  In the case of a vendor string, the field
+                        *  name is undefined; only the field value is relevant.
+                        *
+                        *  A \a field as used in the methods refers to an
+                        *  entire 'NAME=VALUE' string; for convenience the
+                        *  string is NUL-terminated.  A length field is
+                        *  required in the unlikely event that the value
+                        *  contains contain embedded NULs.
+                        *
+                        *  A \a field_name is what is on the left side of the
+                        *  first '=' in the \a field.  By definition it is ASCII
+                        *  and so is NUL-terminated and does not require a
+                        *  length to describe it.  \a field_name is undefined
+                        *  for a vendor string entry.
+                        *
+                        *  A \a field_value is what is on the right side of the
+                        *  first '=' in the \a field.  By definition, this may
+                        *  contain embedded NULs and so a \a field_value_length
+                        *  is required to describe it.  However in practice,
+                        *  embedded NULs are not known to be used, so it is
+                        *  generally safe to treat field values as NUL-
+                        *  terminated UTF-8 strings.
+                        *
+                        *  Always check is_valid() after the constructor or operator=
+                        *  to make sure memory was properly allocated and that the
+                        *  Entry conforms to the Vorbis comment specification.
+                        */
+                       class FLACPP_API Entry {
+                       public:
+                               Entry();
+
+                               Entry(const char *field, unsigned field_length);
+                               Entry(const char *field); // assumes \a field is NUL-terminated
+
+                               Entry(const char *field_name, const char *field_value, unsigned field_value_length);
+                               Entry(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated
+
+                               Entry(const Entry &entry);
+
+                               Entry &operator=(const Entry &entry);
+
+                               virtual ~Entry();
+
+                               virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+                               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(const char *field); // assumes \a field is NUL-terminated
+                               bool set_field_name(const char *field_name);
+                               bool set_field_value(const char *field_value, unsigned field_value_length);
+                               bool set_field_value(const char *field_value); // assumes \a field_value is NUL-terminated
+                       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); // assumes \a field is NUL-terminated
+                               void construct(const char *field_name, const char *field_value, unsigned field_value_length);
+                               void construct(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated
+                               void compose_field();
+                               void parse_field();
+                       };
+
+                       VorbisComment();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline VorbisComment(const VorbisComment &object): Prototype(object) { }
+                       inline VorbisComment(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline VorbisComment(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline VorbisComment(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~VorbisComment();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline VorbisComment &operator=(const VorbisComment &object) { Prototype::operator=(object); return *this; }
+                       inline VorbisComment &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline VorbisComment &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline VorbisComment &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       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;
+                       const FLAC__byte *get_vendor_string() const; // NUL-terminated UTF-8 string
+                       Entry get_comment(unsigned index) const;
+
+                       //! See FLAC__metadata_object_vorbiscomment_set_vendor_string()
+                       bool set_vendor_string(const FLAC__byte *string); // NUL-terminated UTF-8 string
+
+                       //! See FLAC__metadata_object_vorbiscomment_set_comment()
+                       bool set_comment(unsigned index, const Entry &entry);
+
+                       //! See FLAC__metadata_object_vorbiscomment_insert_comment()
+                       bool insert_comment(unsigned index, const Entry &entry);
+
+                       //! See FLAC__metadata_object_vorbiscomment_append_comment()
+                       bool append_comment(const Entry &entry);
+
+                       //! See FLAC__metadata_object_vorbiscomment_delete_comment()
+                       bool delete_comment(unsigned index);
+               };
+
+               /** CUESHEET metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_cuesheet">format specification</A>.
+                */
+               class FLACPP_API CueSheet : public Prototype {
+               public:
+                       /** Convenience class for encapsulating a cue sheet
+                        *  track.
+                        *
+                        *  Always check is_valid() after the constructor or operator=
+                        *  to make sure memory was properly allocated.
+                        */
+                       class FLACPP_API Track {
+                       protected:
+                               ::FLAC__StreamMetadata_CueSheet_Track *object_;
+                       public:
+                               Track();
+                               Track(const ::FLAC__StreamMetadata_CueSheet_Track *track);
+                               Track(const Track &track);
+                               Track &operator=(const Track &track);
+
+                               virtual ~Track();
+
+                               virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+
+                               inline FLAC__uint64 get_offset() const { return object_->offset; }
+                               inline FLAC__byte get_number() const { return object_->number; }
+                               inline const char *get_isrc() const { return object_->isrc; }
+                               inline unsigned get_type() const { return object_->type; }
+                               inline bool get_pre_emphasis() const { return object_->pre_emphasis; }
+
+                               inline FLAC__byte get_num_indices() const { return object_->num_indices; }
+                               ::FLAC__StreamMetadata_CueSheet_Index get_index(unsigned i) const;
+
+                               inline const ::FLAC__StreamMetadata_CueSheet_Track *get_track() const { return object_; }
+
+                               inline void set_offset(FLAC__uint64 value) { object_->offset = value; }
+                               inline void set_number(FLAC__byte value) { object_->number = value; }
+                               void set_isrc(const char value[12]);
+                               void set_type(unsigned value);
+                               inline void set_pre_emphasis(bool value) { object_->pre_emphasis = value? 1 : 0; }
+
+                               void set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+                               //@@@ It's awkward but to insert/delete index points
+                               //@@@ you must use the routines in the CueSheet class.
+                       };
+
+                       CueSheet();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline CueSheet(const CueSheet &object): Prototype(object) { }
+                       inline CueSheet(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline CueSheet(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline CueSheet(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~CueSheet();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline CueSheet &operator=(const CueSheet &object) { Prototype::operator=(object); return *this; }
+                       inline CueSheet &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline CueSheet &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline CueSheet &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       inline bool operator==(const CueSheet &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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       inline bool operator!=(const CueSheet &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 char *get_media_catalog_number() const;
+                       FLAC__uint64 get_lead_in() const;
+                       bool get_is_cd() const;
+
+                       unsigned get_num_tracks() const;
+                       Track get_track(unsigned i) const;
+
+                       void set_media_catalog_number(const char value[128]);
+                       void set_lead_in(FLAC__uint64 value);
+                       void set_is_cd(bool value);
+
+                       void set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+
+                       //! See FLAC__metadata_object_cuesheet_track_insert_index()
+                       bool insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index);
+
+                       //! See FLAC__metadata_object_cuesheet_track_delete_index()
+                       bool delete_index(unsigned track_num, unsigned index_num);
+
+                       //! See FLAC__metadata_object_cuesheet_set_track()
+                       bool set_track(unsigned i, const Track &track);
+
+                       //! See FLAC__metadata_object_cuesheet_insert_track()
+                       bool insert_track(unsigned i, const Track &track);
+
+                       //! See FLAC__metadata_object_cuesheet_delete_track()
+                       bool delete_track(unsigned i);
+
+                       //! See FLAC__metadata_object_cuesheet_is_legal()
+                       bool is_legal(bool check_cd_da_subset = false, const char **violation = 0) const;
+
+                       //! See FLAC__metadata_object_cuesheet_calculate_cddb_id()
+                       FLAC__uint32 calculate_cddb_id() const;
+               };
+
+               /** PICTURE metadata block.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                *  and the <A HREF="../format.html#metadata_block_picture">format specification</A>.
+                */
+               class FLACPP_API Picture : public Prototype {
+               public:
+                       Picture();
+
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline Picture(const Picture &object): Prototype(object) { }
+                       inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~Picture();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; }
+                       inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       inline bool operator==(const Picture &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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       inline bool operator!=(const Picture &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); }
+                       //@}
+
+                       ::FLAC__StreamMetadata_Picture_Type get_type() const;
+                       const char *get_mime_type() const; // NUL-terminated printable ASCII string
+                       const FLAC__byte *get_description() const; // NUL-terminated UTF-8 string
+                       FLAC__uint32 get_width() const;
+                       FLAC__uint32 get_height() const;
+                       FLAC__uint32 get_depth() const;
+                       FLAC__uint32 get_colors() const; ///< a return value of \c 0 means true-color, i.e. 2^depth colors
+                       FLAC__uint32 get_data_length() const;
+                       const FLAC__byte *get_data() const;
+
+                       void set_type(::FLAC__StreamMetadata_Picture_Type type);
+
+                       //! See FLAC__metadata_object_picture_set_mime_type()
+                       bool set_mime_type(const char *string); // NUL-terminated printable ASCII string
+
+                       //! See FLAC__metadata_object_picture_set_description()
+                       bool set_description(const FLAC__byte *string); // NUL-terminated UTF-8 string
+
+                       void set_width(FLAC__uint32 value) const;
+                       void set_height(FLAC__uint32 value) const;
+                       void set_depth(FLAC__uint32 value) const;
+                       void set_colors(FLAC__uint32 value) const; ///< a value of \c 0 means true-color, i.e. 2^depth colors
+
+                       //! See FLAC__metadata_object_picture_set_data()
+                       bool set_data(const FLAC__byte *data, FLAC__uint32 data_length);
+               };
+
+               /** Opaque metadata block for storing unknown types.
+                *  This should not be used unless you know what you are doing;
+                *  it is currently used only internally to support forward
+                *  compatibility of metadata blocks.
+                *  See the \link flacpp_metadata_object overview \endlink for more,
+                */
+               class FLACPP_API Unknown : public Prototype {
+               public:
+                       Unknown();
+                       //
+                       //@{
+                       /** Constructs a copy of the given object.  This form
+                        *  always performs a deep copy.
+                        */
+                       inline Unknown(const Unknown &object): Prototype(object) { }
+                       inline Unknown(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+                       inline Unknown(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+                       //@}
+
+                       /** Constructs an object with copy control.  See
+                        *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Unknown(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+                       ~Unknown();
+
+                       //@{
+                       /** Assign from another object.  Always performs a deep copy. */
+                       inline Unknown &operator=(const Unknown &object) { Prototype::operator=(object); return *this; }
+                       inline Unknown &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+                       inline Unknown &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+                       //@}
+
+                       /** Assigns an object with copy control.  See
+                        *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+                        */
+                       inline Unknown &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+                       //@{
+                       /** Check for equality, performing a deep compare by following pointers. */
+                       inline bool operator==(const Unknown &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); }
+                       //@}
+
+                       //@{
+                       /** Check for inequality, performing a deep compare by following pointers. */
+                       inline bool operator!=(const Unknown &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_data() const;
+
+                       //! This form always copies \a data
+                       bool set_data(const FLAC__byte *data, unsigned length);
+                       bool set_data(FLAC__byte *data, unsigned length, bool copy);
+               };
+
+               /* \} */
+
+
+               /** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface
+                *  \ingroup flacpp_metadata
+                *
+                *  \brief
+                *  Level 0 metadata iterators.
+                *
+                *  See the \link flac_metadata_level0 C layer equivalent \endlink
+                *  for more.
+                *
+                * \{
+                */
+
+               FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); ///< See FLAC__metadata_get_streaminfo().
+
+               FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); ///< See FLAC__metadata_get_tags().
+               FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); ///< See FLAC__metadata_get_tags().
+
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); ///< See FLAC__metadata_get_cuesheet().
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); ///< See FLAC__metadata_get_cuesheet().
+
+               FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors); ///< See FLAC__metadata_get_picture().
+               FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors); ///< See FLAC__metadata_get_picture().
+
+               /* \} */
+
+
+               /** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface
+                *  \ingroup flacpp_metadata
+                *
+                *  \brief
+                *  Level 1 metadata iterator.
+                *
+                *  The flow through the iterator in the C++ layer is similar
+                *  to the C layer:
+                *    - Create a SimpleIterator instance
+                *    - Check SimpleIterator::is_valid()
+                *    - Call SimpleIterator::init() and check the return
+                *    - Traverse and/or edit.  Edits are written to file
+                *      immediately.
+                *    - Destroy the SimpleIterator instance
+                *
+                *  The ownership of pointers in the C++ layer follows that in
+                *  the C layer, i.e.
+                *    - The objects returned by get_block() are yours to
+                *      modify, but changes are not reflected in the FLAC file
+                *      until you call set_block().  The objects are also
+                *      yours to delete; they are not automatically deleted
+                *      when passed to set_block() or insert_block_after().
+                *
+                *  See the \link flac_metadata_level1 C layer equivalent \endlink
+                *  for more.
+                *
+                * \{
+                */
+
+               /** This class is a wrapper around the FLAC__metadata_simple_iterator
+                *  structures and methods; see the
+                * \link flacpp_metadata_level1 usage guide \endlink and
+                * ::FLAC__Metadata_SimpleIterator.
+                */
+               class FLACPP_API SimpleIterator {
+               public:
+                       /** This class is a wrapper around FLAC__Metadata_SimpleIteratorStatus.
+                        */
+                       class FLACPP_API Status {
+                       public:
+                               inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { }
+                               inline operator ::FLAC__Metadata_SimpleIteratorStatus() const { return status_; }
+                               inline const char *as_cstring() const { return ::FLAC__Metadata_SimpleIteratorStatusString[status_]; }
+                       protected:
+                               ::FLAC__Metadata_SimpleIteratorStatus status_;
+                       };
+
+                       SimpleIterator();
+                       virtual ~SimpleIterator();
+
+                       bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+                       bool init(const char *filename, bool read_only, bool preserve_file_stats); ///< See FLAC__metadata_simple_iterator_init().
+
+                       Status status();                                                    ///< See FLAC__metadata_simple_iterator_status().
+                       bool is_writable() const;                                           ///< See FLAC__metadata_simple_iterator_is_writable().
+
+                       bool next();                                                        ///< See FLAC__metadata_simple_iterator_next().
+                       bool prev();                                                        ///< See FLAC__metadata_simple_iterator_prev().
+                       bool is_last() const;                                               ///< See FLAC__metadata_simple_iterator_is_last().
+
+                       off_t get_block_offset() const;                                     ///< See FLAC__metadata_simple_iterator_get_block_offset().
+                       ::FLAC__MetadataType get_block_type() const;                        ///< See FLAC__metadata_simple_iterator_get_block_type().
+                       unsigned get_block_length() const;                                  ///< See FLAC__metadata_simple_iterator_get_block_length().
+                       bool get_application_id(FLAC__byte *id);                            ///< See FLAC__metadata_simple_iterator_get_application_id().
+                       Prototype *get_block();                                             ///< See FLAC__metadata_simple_iterator_get_block().
+                       bool set_block(Prototype *block, bool use_padding = true);          ///< See FLAC__metadata_simple_iterator_set_block().
+                       bool insert_block_after(Prototype *block, bool use_padding = true); ///< See FLAC__metadata_simple_iterator_insert_block_after().
+                       bool delete_block(bool use_padding = true);                         ///< See FLAC__metadata_simple_iterator_delete_block().
+
+               protected:
+                       ::FLAC__Metadata_SimpleIterator *iterator_;
+                       void clear();
+               };
+
+               /* \} */
+
+
+               /** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface
+                *  \ingroup flacpp_metadata
+                *
+                *  \brief
+                *  Level 2 metadata iterator.
+                *
+                *  The flow through the iterator in the C++ layer is similar
+                *  to the C layer:
+                *    - Create a Chain instance
+                *    - Check Chain::is_valid()
+                *    - Call Chain::read() and check the return
+                *    - Traverse and/or edit with an Iterator or with
+                *      Chain::merge_padding() or Chain::sort_padding()
+                *    - Write changes back to FLAC file with Chain::write()
+                *    - Destroy the Chain instance
+                *
+                *  The ownership of pointers in the C++ layer is slightly
+                *  different than in the C layer, i.e.
+                *    - The objects returned by Iterator::get_block() are NOT
+                *      owned by the iterator and should be deleted by the
+                *      caller when finished, BUT, when you modify the block,
+                *      it will directly edit what's in the chain and you do
+                *      not need to call Iterator::set_block().  However the
+                *      changes will not be reflected in the FLAC file until
+                *      the chain is written with Chain::write().
+                *    - When you pass an object to Iterator::set_block(),
+                *      Iterator::insert_block_before(), or
+                *      Iterator::insert_block_after(), the iterator takes
+                *      ownership of the block and it will be deleted by the
+                *      chain.
+                *
+                *  See the \link flac_metadata_level2 C layer equivalent \endlink
+                *  for more.
+                *
+                * \{
+                */
+
+               /** This class is a wrapper around the FLAC__metadata_chain
+                *  structures and methods; see the
+                * \link flacpp_metadata_level2 usage guide \endlink and
+                * ::FLAC__Metadata_Chain.
+                */
+               class FLACPP_API Chain {
+               public:
+                       /** This class is a wrapper around FLAC__Metadata_ChainStatus.
+                        */
+                       class FLACPP_API Status {
+                       public:
+                               inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { }
+                               inline operator ::FLAC__Metadata_ChainStatus() const { return status_; }
+                               inline const char *as_cstring() const { return ::FLAC__Metadata_ChainStatusString[status_]; }
+                       protected:
+                               ::FLAC__Metadata_ChainStatus status_;
+                       };
+
+                       Chain();
+                       virtual ~Chain();
+
+                       friend class Iterator;
+
+                       bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+                       Status status();                                                ///< See FLAC__metadata_chain_status().
+
+                       bool read(const char *filename, bool is_ogg = false);                                ///< See FLAC__metadata_chain_read(), FLAC__metadata_chain_read_ogg().
+                       bool read(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, bool is_ogg = false);  ///< See FLAC__metadata_chain_read_with_callbacks(), FLAC__metadata_chain_read_ogg_with_callbacks().
+
+                       bool check_if_tempfile_needed(bool use_padding);                ///< See FLAC__metadata_chain_check_if_tempfile_needed().
+
+                       bool write(bool use_padding = true, bool preserve_file_stats = false); ///< See FLAC__metadata_chain_write().
+                       bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks); ///< See FLAC__metadata_chain_write_with_callbacks().
+                       bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks); ///< See FLAC__metadata_chain_write_with_callbacks_and_tempfile().
+
+                       void merge_padding();                                           ///< See FLAC__metadata_chain_merge_padding().
+                       void sort_padding();                                            ///< See FLAC__metadata_chain_sort_padding().
+
+               protected:
+                       ::FLAC__Metadata_Chain *chain_;
+                       virtual void clear();
+               };
+
+               /** This class is a wrapper around the FLAC__metadata_iterator
+                *  structures and methods; see the
+                * \link flacpp_metadata_level2 usage guide \endlink and
+                * ::FLAC__Metadata_Iterator.
+                */
+               class FLACPP_API Iterator {
+               public:
+                       Iterator();
+                       virtual ~Iterator();
+
+                       bool is_valid() const; ///< Returns \c true iff object was properly constructed.
+
+
+                       void init(Chain &chain);                       ///< See FLAC__metadata_iterator_init().
+
+                       bool next();                                   ///< See FLAC__metadata_iterator_next().
+                       bool prev();                                   ///< See FLAC__metadata_iterator_prev().
+
+                       ::FLAC__MetadataType get_block_type() const;   ///< See FLAC__metadata_iterator_get_block_type().
+                       Prototype *get_block();                        ///< See FLAC__metadata_iterator_get_block().
+                       bool set_block(Prototype *block);              ///< See FLAC__metadata_iterator_set_block().
+                       bool delete_block(bool replace_with_padding);  ///< See FLAC__metadata_iterator_delete_block().
+                       bool insert_block_before(Prototype *block);    ///< See FLAC__metadata_iterator_insert_block_before().
+                       bool insert_block_after(Prototype *block);     ///< See FLAC__metadata_iterator_insert_block_after().
+
+               protected:
+                       ::FLAC__Metadata_Iterator *iterator_;
+                       virtual void clear();
+               };
+
+               /* \} */
+
+       }
+}
+
+#endif
diff --git a/include/FLAC/Makefile.am b/include/FLAC/Makefile.am
new file mode 100644 (file)
index 0000000..19f49b1
--- /dev/null
@@ -0,0 +1,42 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+flaccincludedir = $(includedir)/FLAC
+
+flaccinclude_HEADERS = \
+       all.h \
+       assert.h \
+       callback.h \
+       export.h \
+       format.h \
+       metadata.h \
+       ordinals.h \
+       stream_decoder.h \
+       stream_encoder.h
diff --git a/include/FLAC/all.h b/include/FLAC/all.h
new file mode 100644 (file)
index 0000000..c542c0d
--- /dev/null
@@ -0,0 +1,370 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ALL_H
+#define FLAC__ALL_H
+
+#include "export.h"
+
+#include "assert.h"
+#include "callback.h"
+#include "format.h"
+#include "metadata.h"
+#include "ordinals.h"
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+/** \mainpage
+ *
+ * \section intro Introduction
+ *
+ * This is the documentation for the FLAC C and C++ APIs.  It is
+ * highly interconnected; this introduction should give you a top
+ * level idea of the structure and how to find the information you
+ * need.  As a prerequisite you should have at least a basic
+ * knowledge of the FLAC format, documented
+ * <A HREF="../format.html">here</A>.
+ *
+ * \section c_api FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files.  The public include files will be installed
+ * in your include area (for example /usr/include/FLAC/...).
+ *
+ * By writing a little code and linking against libFLAC, it is
+ * relatively easy to add FLAC support to another program.  The
+ * library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
+ * Complete source code of libFLAC as well as the command-line
+ * encoder and plugins is available and is a useful source of
+ * examples.
+ *
+ * Aside from encoders and decoders, libFLAC provides a powerful
+ * metadata interface for manipulating metadata in FLAC files.  It
+ * allows the user to add, delete, and modify FLAC metadata blocks
+ * and it can automatically take advantage of PADDING blocks to avoid
+ * rewriting the entire FLAC file when changing the size of the
+ * metadata.
+ *
+ * libFLAC usually only requires the standard C library and C math
+ * library. In particular, threading is not used so there is no
+ * dependency on a thread library. However, libFLAC does not use
+ * global variables and should be thread-safe.
+ *
+ * libFLAC also supports encoding to and decoding from Ogg FLAC.
+ * However the metadata editing interfaces currently have limited
+ * read-only support for Ogg FLAC files.
+ *
+ * \section cpp_api FLAC C++ API
+ *
+ * The FLAC C++ API is a set of classes that encapsulate the
+ * structures and functions in libFLAC.  They provide slightly more
+ * functionality with respect to metadata but are otherwise
+ * equivalent.  For the most part, they share the same usage as
+ * their counterparts in libFLAC, and the FLAC C API documentation
+ * can be used as a supplement.  The public include files
+ * for the C++ API will be installed in your include area (for
+ * example /usr/include/FLAC++/...).
+ *
+ * libFLAC++ is also licensed under
+ * <A HREF="../license.html">Xiph's BSD license</A>.
+ *
+ * \section getting_started Getting Started
+ *
+ * A good starting point for learning the API is to browse through
+ * the <A HREF="modules.html">modules</A>.  Modules are logical
+ * groupings of related functions or classes, which correspond roughly
+ * to header files or sections of header files.  Each module includes a
+ * detailed description of the general usage of its functions or
+ * classes.
+ *
+ * From there you can go on to look at the documentation of
+ * individual functions.  You can see different views of the individual
+ * functions through the links in top bar across this page.
+ *
+ * If you prefer a more hands-on approach, you can jump right to some
+ * <A HREF="../documentation_example_code.html">example code</A>.
+ *
+ * \section porting_guide Porting Guide
+ *
+ * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink
+ * has been introduced which gives detailed instructions on how to
+ * port your code to newer versions of FLAC.
+ *
+ * \section embedded_developers Embedded Developers
+ *
+ * libFLAC has grown larger over time as more functionality has been
+ * included, but much of it may be unnecessary for a particular embedded
+ * implementation.  Unused parts may be pruned by some simple editing of
+ * src/libFLAC/Makefile.am.  In general, the decoders, encoders, and
+ * metadata interface are all independent from each other.
+ *
+ * It is easiest to just describe the dependencies:
+ *
+ * - All modules depend on the \link flac_format Format \endlink module.
+ * - The decoders and encoders depend on the bitbuffer.
+ * - The decoder is independent of the encoder.  The encoder uses the
+ *   decoder because of the verify feature, but this can be removed if
+ *   not needed.
+ * - Parts of the metadata interface require the stream decoder (but not
+ *   the encoder).
+ * - Ogg support is selectable through the compile time macro
+ *   \c FLAC__HAS_OGG.
+ *
+ * For example, if your application only requires the stream decoder, no
+ * encoder, and no metadata interface, you can remove the stream encoder
+ * and the metadata interface, which will greatly reduce the size of the
+ * library.
+ *
+ * Also, there are several places in the libFLAC code with comments marked
+ * with "OPT:" where a #define can be changed to enable code that might be
+ * faster on a specific platform.  Experimenting with these can yield faster
+ * binaries.
+ */
+
+/** \defgroup porting Porting Guide for New Versions
+ *
+ * This module describes differences in the library interfaces from
+ * version to version.  It assists in the porting of code that uses
+ * the libraries to newer versions of FLAC.
+ *
+ * One simple facility for making porting easier that has been added
+ * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
+ * library's includes (e.g. \c include/FLAC/export.h).  The
+ * \c #defines mirror the libraries'
+ * <A HREF="http://www.gnu.org/software/libtool/manual.html#Libtool-versioning">libtool version numbers</A>,
+ * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
+ * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
+ * These can be used to support multiple versions of an API during the
+ * transition phase, e.g.
+ *
+ * \code
+ * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
+ *   legacy code
+ * #else
+ *   new code
+ * #endif
+ * \endcode
+ *
+ * The the source will work for multiple versions and the legacy code can
+ * easily be removed when the transition is complete.
+ *
+ * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
+ * include/FLAC/export.h), which can be used to determine whether or not
+ * the library has been compiled with support for Ogg FLAC.  This is
+ * simpler than trying to call an Ogg init function and catching the
+ * error.
+ */
+
+/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.2 to FLAC 1.1.3.
+ *
+ * The main change between the APIs in 1.1.2 and 1.1.3 is that they have
+ * been simplified.  First, libOggFLAC has been merged into libFLAC and
+ * libOggFLAC++ has been merged into libFLAC++.  Second, both the three
+ * decoding layers and three encoding layers have been merged into a
+ * single stream decoder and stream encoder.  That is, the functionality
+ * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged
+ * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and
+ * FLAC__FileEncoder into FLAC__StreamEncoder.  Only the
+ * FLAC__StreamDecoder and FLAC__StreamEncoder remain.  What this means
+ * is there is now a single API that can be used to encode or decode
+ * streams to/from native FLAC or Ogg FLAC and the single API can work
+ * on both seekable and non-seekable streams.
+ *
+ * Instead of creating an encoder or decoder of a certain layer, now the
+ * client will always create a FLAC__StreamEncoder or
+ * FLAC__StreamDecoder.  The old layers are now differentiated by the
+ * initialization function.  For example, for the decoder,
+ * FLAC__stream_decoder_init() has been replaced by
+ * FLAC__stream_decoder_init_stream().  This init function takes
+ * callbacks for the I/O, and the seeking callbacks are optional.  This
+ * allows the client to use the same object for seekable and
+ * non-seekable streams.  For decoding a FLAC file directly, the client
+ * can use FLAC__stream_decoder_init_file() and pass just a filename
+ * and fewer callbacks; most of the other callbacks are supplied
+ * internally.  For situations where fopen()ing by filename is not
+ * possible (e.g. Unicode filenames on Windows) the client can instead
+ * open the file itself and supply the FILE* to
+ * FLAC__stream_decoder_init_FILE().  The init functions now returns a
+ * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState.
+ * Since the callbacks and client data are now passed to the init
+ * function, the FLAC__stream_decoder_set_*_callback() functions and
+ * FLAC__stream_decoder_set_client_data() are no longer needed.  The
+ * rest of the calls to the decoder are the same as before.
+ *
+ * There are counterpart init functions for Ogg FLAC, e.g.
+ * FLAC__stream_decoder_init_ogg_stream().  All the rest of the calls
+ * and callbacks are the same as for native FLAC.
+ *
+ * As an example, in FLAC 1.1.2 a seekable stream decoder would have
+ * been set up like so:
+ *
+ * \code
+ * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback);
+ * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback);
+ * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback);
+ * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback);
+ * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback);
+ * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback);
+ * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback);
+ * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback);
+ * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data);
+ * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something;
+ * \endcode
+ *
+ * In FLAC 1.1.3 it is like this:
+ *
+ * \code
+ * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * if(FLAC__stream_decoder_init_stream(
+ *   decoder,
+ *   my_read_callback,
+ *   my_seek_callback,      // or NULL
+ *   my_tell_callback,      // or NULL
+ *   my_length_callback,    // or NULL
+ *   my_eof_callback,       // or NULL
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or you could do;
+ *
+ * \code
+ * [...]
+ * FILE *file = fopen("somefile.flac","rb");
+ * if(file == NULL) do_somthing;
+ * if(FLAC__stream_decoder_init_FILE(
+ *   decoder,
+ *   file,
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or just:
+ *
+ * \code
+ * [...]
+ * if(FLAC__stream_decoder_init_file(
+ *   decoder,
+ *   "somefile.flac",
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * Another small change to the decoder is in how it handles unparseable
+ * streams.  Before, when the decoder found an unparseable stream
+ * (reserved for when the decoder encounters a stream from a future
+ * encoder that it can't parse), it changed the state to
+ * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM.  Now the decoder instead
+ * drops sync and calls the error callback with a new error code
+ * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM.  This is
+ * more robust.  If your error callback does not discriminate on the the
+ * error state, your code does not need to be changed.
+ *
+ * The encoder now has a new setting:
+ * FLAC__stream_encoder_set_apodization().  This is for setting the
+ * method used to window the data before LPC analysis.  You only need to
+ * add a call to this function if the default is not suitable.   There
+ * are also two new convenience functions that may be useful:
+ * FLAC__metadata_object_cuesheet_calculate_cddb_id() and
+ * FLAC__metadata_get_cuesheet().
+ *
+ * The \a bytes parameter to FLAC__StreamDecoderReadCallback,
+ * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
+ * is now \c size_t instead of \c unsigned.
+ */
+
+/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.3 to FLAC 1.1.4.
+ *
+ * There were no changes to any of the interfaces from 1.1.3 to 1.1.4.
+ * There was a slight change in the implementation of
+ * FLAC__stream_encoder_set_metadata(); the function now makes a copy
+ * of the \a metadata array of pointers so the client no longer needs
+ * to maintain it after the call.  The objects themselves that are
+ * pointed to by the array are still not copied though and must be
+ * maintained until the call to FLAC__stream_encoder_finish().
+ */
+
+/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.4 to FLAC 1.2.0.
+ *
+ * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0.
+ * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added.
+ * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added.
+ *
+ * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN
+ * has changed to reflect the conversion of one of the reserved bits
+ * into active use.  It used to be \c 2 and now is \c 1.  However the
+ * FLAC frame header length has not changed, so to skip the proper
+ * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN +
+ * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN
+ */
+
+/** \defgroup flac FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files.
+ *
+ * You should start with the format components as all other modules
+ * are dependent on it.
+ */
+
+#endif
diff --git a/include/FLAC/assert.h b/include/FLAC/assert.h
new file mode 100644 (file)
index 0000000..3fc03f3
--- /dev/null
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ASSERT_H
+#define FLAC__ASSERT_H
+
+/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
+#ifdef DEBUG
+#include <assert.h>
+#define FLAC__ASSERT(x) assert(x)
+#define FLAC__ASSERT_DECLARATION(x) x
+#else
+#define FLAC__ASSERT(x)
+#define FLAC__ASSERT_DECLARATION(x)
+#endif
+
+#endif
diff --git a/include/FLAC/callback.h b/include/FLAC/callback.h
new file mode 100644 (file)
index 0000000..c954121
--- /dev/null
@@ -0,0 +1,184 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__CALLBACK_H
+#define FLAC__CALLBACK_H
+
+#include "ordinals.h"
+#include <stdlib.h> /* for size_t */
+
+/** \file include/FLAC/callback.h
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  See the detailed documentation for callbacks in the
+ *  \link flac_callbacks callbacks \endlink module.
+ */
+
+/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  The purpose of the I/O callback functions is to create a common way
+ *  for the metadata interfaces to handle I/O.
+ *
+ *  Originally the metadata interfaces required filenames as the way of
+ *  specifying FLAC files to operate on.  This is problematic in some
+ *  environments so there is an additional option to specify a set of
+ *  callbacks for doing I/O on the FLAC file, instead of the filename.
+ *
+ *  In addition to the callbacks, a FLAC__IOHandle type is defined as an
+ *  opaque structure for a data source.
+ *
+ *  The callback function prototypes are similar (but not identical) to the
+ *  stdio functions fread, fwrite, fseek, ftell, feof, and fclose.  If you use
+ *  stdio streams to implement the callbacks, you can pass fread, fwrite, and
+ *  fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
+ *  FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
+ *  is required.  \warning You generally CANNOT directly use fseek or ftell
+ *  for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
+ *  these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
+ *  large files.  You will have to find an equivalent function (e.g. ftello),
+ *  or write a wrapper.  The same is true for feof() since this is usually
+ *  implemented as a macro, not as a function whose address can be taken.
+ *
+ * \{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This is the opaque handle type used by the callbacks.  Typically
+ *  this is a \c FILE* or address of a file descriptor.
+ */
+typedef void* FLAC__IOHandle;
+
+/** Signature for the read callback.
+ *  The signature and semantics match POSIX fread() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the read buffer.
+ * \param  size     The size of the records to be read.
+ * \param  nmemb    The number of records to be read.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records read.
+ */
+typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the write callback.
+ *  The signature and semantics match POSIX fwrite() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the write buffer.
+ * \param  size     The size of the records to be written.
+ * \param  nmemb    The number of records to be written.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records written.
+ */
+typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the seek callback.
+ *  The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \param  offset   The new position, relative to \a whence
+ * \param  whence   \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
+ * \retval int
+ *    \c 0 on success, \c -1 on error.
+ */
+typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+
+/** Signature for the tell callback.
+ *  The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval FLAC__int64
+ *    The current position on success, \c -1 on error.
+ */
+typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
+
+/** Signature for the EOF callback.
+ *  The signature and semantics mostly match POSIX feof() but WATCHOUT:
+ *  on many systems, feof() is a macro, so in this case a wrapper function
+ *  must be provided instead.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 if not at end of file, nonzero if at end of file.
+ */
+typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
+
+/** Signature for the close callback.
+ *  The signature and semantics match POSIX fclose() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 on success, \c EOF on error.
+ */
+typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
+
+/** A structure for holding a set of callbacks.
+ *  Each FLAC interface that requires a FLAC__IOCallbacks structure will
+ *  describe which of the callbacks are required.  The ones that are not
+ *  required may be set to NULL.
+ *
+ *  If the seek requirement for an interface is optional, you can signify that
+ *  a data sorce is not seekable by setting the \a seek field to \c NULL.
+ */
+typedef struct {
+       FLAC__IOCallback_Read read;
+       FLAC__IOCallback_Write write;
+       FLAC__IOCallback_Seek seek;
+       FLAC__IOCallback_Tell tell;
+       FLAC__IOCallback_Eof eof;
+       FLAC__IOCallback_Close close;
+} FLAC__IOCallbacks;
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/FLAC/export.h b/include/FLAC/export.h
new file mode 100644 (file)
index 0000000..a525f29
--- /dev/null
@@ -0,0 +1,91 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__EXPORT_H
+#define FLAC__EXPORT_H
+
+/** \file include/FLAC/export.h
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  See the \link flac_export export \endlink module.
+ */
+
+/** \defgroup flac_export FLAC/export.h: export symbols
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  If you are compiling with MSVC and will link to the static library
+ *  (libFLAC.lib) you should define FLAC__NO_DLL in your project to
+ *  make sure the symbols are exported properly.
+ *
+ * \{
+ */
+
+#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
+#define FLAC_API
+
+#else
+
+#ifdef FLAC_API_EXPORTS
+#define        FLAC_API        _declspec(dllexport)
+#else
+#define FLAC_API       _declspec(dllimport)
+
+#endif
+#endif
+
+/** These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual.html#Libtool-versioning
+ */
+#define FLAC_API_VERSION_CURRENT 10
+#define FLAC_API_VERSION_REVISION 0 /**< see above */
+#define FLAC_API_VERSION_AGE 2 /**< see above */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */
+extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* \} */
+
+#endif
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
new file mode 100644 (file)
index 0000000..77e2d01
--- /dev/null
@@ -0,0 +1,1010 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FORMAT_H
+#define FLAC__FORMAT_H
+
+#include "export.h"
+#include "ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file include/FLAC/format.h
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_format format \endlink module.
+ */
+
+/** \defgroup flac_format FLAC/format.h: format components
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  First, you should be familiar with the
+ *  <A HREF="../format.html">FLAC format</A>.  Many of the values here
+ *  follow directly from the specification.  As a user of libFLAC, the
+ *  interesting parts really are the structures that describe the frame
+ *  header and metadata blocks.
+ *
+ *  The format structures here are very primitive, designed to store
+ *  information in an efficient way.  Reading information from the
+ *  structures is easy but creating or modifying them directly is
+ *  more complex.  For the most part, as a user of a library, editing
+ *  is not necessary; however, for metadata blocks it is, so there are
+ *  convenience functions provided in the \link flac_metadata metadata
+ *  module \endlink to simplify the manipulation of metadata blocks.
+ *
+ * \note
+ * It's not the best convention, but symbols ending in _LEN are in bits
+ * and _LENGTH are in bytes.  _LENGTH symbols are \#defines instead of
+ * global variables because they are usually used when declaring byte
+ * arrays and some compilers require compile-time knowledge of array
+ * sizes when declared on the stack.
+ *
+ * \{
+ */
+
+
+/*
+       Most of the values described in this file are defined by the FLAC
+       format specification.  There is nothing to tune here.
+*/
+
+/** The largest legal metadata type code. */
+#define FLAC__MAX_METADATA_TYPE_CODE (126u)
+
+/** The minimum block size, in samples, permitted by the format. */
+#define FLAC__MIN_BLOCK_SIZE (16u)
+
+/** The maximum block size, in samples, permitted by the format. */
+#define FLAC__MAX_BLOCK_SIZE (65535u)
+
+/** The maximum block size, in samples, permitted by the FLAC subset for
+ *  sample rates up to 48kHz. */
+#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u)
+
+/** The maximum number of channels permitted by the format. */
+#define FLAC__MAX_CHANNELS (8u)
+
+/** The minimum sample resolution permitted by the format. */
+#define FLAC__MIN_BITS_PER_SAMPLE (4u)
+
+/** The maximum sample resolution permitted by the format. */
+#define FLAC__MAX_BITS_PER_SAMPLE (32u)
+
+/** The maximum sample resolution permitted by libFLAC.
+ *
+ * \warning
+ * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format.  However,
+ * the reference encoder/decoder is currently limited to 24 bits because
+ * of prevalent 32-bit math, so make sure and use this value when
+ * appropriate.
+ */
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+
+/** The maximum sample rate permitted by the format.  The value is
+ *  ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
+ *  as to why.
+ */
+#define FLAC__MAX_SAMPLE_RATE (655350u)
+
+/** The maximum LPC order permitted by the format. */
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/** The maximum LPC order permitted by the FLAC subset for sample rates
+ *  up to 48kHz. */
+#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u)
+
+/** The minimum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MIN_QLP_COEFF_PRECISION (5u)
+
+/** The maximum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MAX_QLP_COEFF_PRECISION (15u)
+
+/** The maximum order of the fixed predictors permitted by the format. */
+#define FLAC__MAX_FIXED_ORDER (4u)
+
+/** The maximum Rice partition order permitted by the format. */
+#define FLAC__MAX_RICE_PARTITION_ORDER (15u)
+
+/** The maximum Rice partition order permitted by the FLAC Subset. */
+#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u)
+
+/** The version string of the release, stamped onto the libraries and binaries.
+ *
+ * \note
+ * This does not correspond to the shared library version number, which
+ * is used to determine binary compatibility.
+ */
+extern FLAC_API const char *FLAC__VERSION_STRING;
+
+/** The vendor string inserted by the encoder into the VORBIS_COMMENT block.
+ *  This is a NUL-terminated ASCII string; when inserted into the
+ *  VORBIS_COMMENT the trailing null is stripped.
+ */
+extern FLAC_API const char *FLAC__VENDOR_STRING;
+
+/** The byte string representation of the beginning of a FLAC stream. */
+extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
+
+/** The 32-bit integer big-endian representation of the beginning of
+ *  a FLAC stream.
+ */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
+
+/** The length of the FLAC signature in bits. */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+
+/** The length of the FLAC signature in bytes. */
+#define FLAC__STREAM_SYNC_LENGTH (4u)
+
+
+/*****************************************************************************
+ *
+ * Subframe structures
+ *
+ *****************************************************************************/
+
+/*****************************************************************************/
+
+/** An enumeration of the available entropy coding methods. */
+typedef enum {
+       FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0,
+       /**< Residual is coded by partitioning into contexts, each with it's own
+        * 4-bit Rice parameter. */
+
+       FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1
+       /**< Residual is coded by partitioning into contexts, each with it's own
+        * 5-bit Rice parameter. */
+} FLAC__EntropyCodingMethodType;
+
+/** Maps a FLAC__EntropyCodingMethodType to a C string.
+ *
+ *  Using a FLAC__EntropyCodingMethodType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
+
+
+/** Contents of a Rice partitioned residual
+ */
+typedef struct {
+
+       unsigned *parameters;
+       /**< The Rice parameters for each context. */
+
+       unsigned *raw_bits;
+       /**< Widths for escape-coded partitions.  Will be non-zero for escaped
+        * partitions and zero for unescaped partitions.
+        */
+
+       unsigned capacity_by_order;
+       /**< The capacity of the \a parameters and \a raw_bits arrays
+        * specified as an order, i.e. the number of array elements
+        * allocated is 2 ^ \a capacity_by_order.
+        */
+} FLAC__EntropyCodingMethod_PartitionedRiceContents;
+
+/** Header for a Rice partitioned residual.  (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+ */
+typedef struct {
+
+       unsigned order;
+       /**< The partition order, i.e. # of contexts = 2 ^ \a order. */
+
+       const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
+       /**< The context's Rice parameters and/or raw bits. */
+
+} FLAC__EntropyCodingMethod_PartitionedRice;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+/** Header for the entropy coding method.  (c.f. <A HREF="../format.html#residual">format specification</A>)
+ */
+typedef struct {
+       FLAC__EntropyCodingMethodType type;
+       union {
+               FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
+       } data;
+} FLAC__EntropyCodingMethod;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+
+/*****************************************************************************/
+
+/** An enumeration of the available subframe types. */
+typedef enum {
+       FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */
+       FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */
+       FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */
+       FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */
+} FLAC__SubframeType;
+
+/** Maps a FLAC__SubframeType to a C string.
+ *
+ *  Using a FLAC__SubframeType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SubframeTypeString[];
+
+
+/** CONSTANT subframe.  (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+ */
+typedef struct {
+       FLAC__int32 value; /**< The constant signal value. */
+} FLAC__Subframe_Constant;
+
+
+/** VERBATIM subframe.  (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+ */
+typedef struct {
+       const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+} FLAC__Subframe_Verbatim;
+
+
+/** FIXED subframe.  (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+ */
+typedef struct {
+       FLAC__EntropyCodingMethod entropy_coding_method;
+       /**< The residual coding method. */
+
+       unsigned order;
+       /**< The polynomial order. */
+
+       FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+       /**< Warmup samples to prime the predictor, length == order. */
+
+       const FLAC__int32 *residual;
+       /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_Fixed;
+
+
+/** LPC subframe.  (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+ */
+typedef struct {
+       FLAC__EntropyCodingMethod entropy_coding_method;
+       /**< The residual coding method. */
+
+       unsigned order;
+       /**< The FIR order. */
+
+       unsigned qlp_coeff_precision;
+       /**< Quantized FIR filter coefficient precision in bits. */
+
+       int quantization_level;
+       /**< The qlp coeff shift needed. */
+
+       FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+       /**< FIR filter coefficients. */
+
+       FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+       /**< Warmup samples to prime the predictor, length == order. */
+
+       const FLAC__int32 *residual;
+       /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_LPC;
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+
+
+/** FLAC subframe structure.  (c.f. <A HREF="../format.html#subframe">format specification</A>)
+ */
+typedef struct {
+       FLAC__SubframeType type;
+       union {
+               FLAC__Subframe_Constant constant;
+               FLAC__Subframe_Fixed fixed;
+               FLAC__Subframe_LPC lpc;
+               FLAC__Subframe_Verbatim verbatim;
+       } data;
+       unsigned wasted_bits;
+} FLAC__Subframe;
+
+/** == 1 (bit)
+ *
+ * This used to be a zero-padding bit (hence the name
+ * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit.  It still has a
+ * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
+ * to mean something else.
+ */
+extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN;
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Frame structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available channel assignments. */
+typedef enum {
+       FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */
+       FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */
+       FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */
+       FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */
+} FLAC__ChannelAssignment;
+
+/** Maps a FLAC__ChannelAssignment to a C string.
+ *
+ *  Using a FLAC__ChannelAssignment as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__ChannelAssignmentString[];
+
+/** An enumeration of the possible frame numbering methods. */
+typedef enum {
+       FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */
+       FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */
+} FLAC__FrameNumberType;
+
+/** Maps a FLAC__FrameNumberType to a C string.
+ *
+ *  Using a FLAC__FrameNumberType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
+
+
+/** FLAC frame header structure.  (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+ */
+typedef struct {
+       unsigned blocksize;
+       /**< The number of samples per subframe. */
+
+       unsigned sample_rate;
+       /**< The sample rate in Hz. */
+
+       unsigned channels;
+       /**< The number of channels (== number of subframes). */
+
+       FLAC__ChannelAssignment channel_assignment;
+       /**< The channel assignment for the frame. */
+
+       unsigned bits_per_sample;
+       /**< The sample resolution. */
+
+       FLAC__FrameNumberType number_type;
+       /**< The numbering scheme used for the frame.  As a convenience, the
+        * decoder will always convert a frame number to a sample number because
+        * the rules are complex. */
+
+       union {
+               FLAC__uint32 frame_number;
+               FLAC__uint64 sample_number;
+       } number;
+       /**< The frame number or sample number of first sample in frame;
+        * use the \a number_type value to determine which to use. */
+
+       FLAC__uint8 crc;
+       /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+        * of the raw frame header bytes, meaning everything before the CRC byte
+        * including the sync code.
+        */
+} FLAC__FrameHeader;
+
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+
+
+/** FLAC frame footer structure.  (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+ */
+typedef struct {
+       FLAC__uint16 crc;
+       /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with
+        * 0) of the bytes before the crc, back to and including the frame header
+        * sync code.
+        */
+} FLAC__FrameFooter;
+
+extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+
+
+/** FLAC frame structure.  (c.f. <A HREF="../format.html#frame">format specification</A>)
+ */
+typedef struct {
+       FLAC__FrameHeader header;
+       FLAC__Subframe subframes[FLAC__MAX_CHANNELS];
+       FLAC__FrameFooter footer;
+} FLAC__Frame;
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Meta-data structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available metadata block types. */
+typedef enum {
+
+       FLAC__METADATA_TYPE_STREAMINFO = 0,
+       /**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
+       FLAC__METADATA_TYPE_PADDING = 1,
+       /**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+
+       FLAC__METADATA_TYPE_APPLICATION = 2,
+       /**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+
+       FLAC__METADATA_TYPE_SEEKTABLE = 3,
+       /**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+
+       FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+       /**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
+
+       FLAC__METADATA_TYPE_CUESHEET = 5,
+       /**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+
+       FLAC__METADATA_TYPE_PICTURE = 6,
+       /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+       FLAC__METADATA_TYPE_UNDEFINED = 7
+       /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
+
+} FLAC__MetadataType;
+
+/** Maps a FLAC__MetadataType to a C string.
+ *
+ *  Using a FLAC__MetadataType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__MetadataTypeString[];
+
+
+/** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+ */
+typedef struct {
+       unsigned min_blocksize, max_blocksize;
+       unsigned min_framesize, max_framesize;
+       unsigned sample_rate;
+       unsigned channels;
+       unsigned bits_per_sample;
+       FLAC__uint64 total_samples;
+       FLAC__byte md5sum[16];
+} FLAC__StreamMetadata_StreamInfo;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+
+/** The total stream length of the STREAMINFO block in bytes. */
+#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
+
+/** FLAC PADDING structure.  (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+ */
+typedef struct {
+       int dummy;
+       /**< Conceptually this is an empty struct since we don't store the
+        * padding bytes.  Empty structs are not allowed by some C compilers,
+        * hence the dummy.
+        */
+} FLAC__StreamMetadata_Padding;
+
+
+/** FLAC APPLICATION structure.  (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+ */
+typedef struct {
+       FLAC__byte id[4];
+       FLAC__byte *data;
+} FLAC__StreamMetadata_Application;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+
+/** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+ */
+typedef struct {
+       FLAC__uint64 sample_number;
+       /**<  The sample number of the target frame. */
+
+       FLAC__uint64 stream_offset;
+       /**< The offset, in bytes, of the target frame with respect to
+        * beginning of the first frame. */
+
+       unsigned frame_samples;
+       /**< The number of samples in the target frame. */
+} FLAC__StreamMetadata_SeekPoint;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+
+/** The total stream length of a seek point in bytes. */
+#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
+
+/** The value used in the \a sample_number field of
+ *  FLAC__StreamMetadataSeekPoint used to indicate a placeholder
+ *  point (== 0xffffffffffffffff).
+ */
+extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+
+
+/** FLAC SEEKTABLE structure.  (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+ *
+ * \note From the format specification:
+ * - The seek points must be sorted by ascending sample number.
+ * - Each seek point's sample number must be the first sample of the
+ *   target frame.
+ * - Each seek point's sample number must be unique within the table.
+ * - Existence of a SEEKTABLE block implies a correct setting of
+ *   total_samples in the stream_info block.
+ * - Behavior is undefined when more than one SEEKTABLE block is
+ *   present in a stream.
+ */
+typedef struct {
+       unsigned num_points;
+       FLAC__StreamMetadata_SeekPoint *points;
+} FLAC__StreamMetadata_SeekTable;
+
+
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ *  For convenience, the APIs maintain a trailing NUL character at the end of
+ *  \a entry which is not counted toward \a length, i.e.
+ *  \code strlen(entry) == length \endcode
+ */
+typedef struct {
+       FLAC__uint32 length;
+       FLAC__byte *entry;
+} FLAC__StreamMetadata_VorbisComment_Entry;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+       FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+       FLAC__uint32 num_comments;
+       FLAC__StreamMetadata_VorbisComment_Entry *comments;
+} FLAC__StreamMetadata_VorbisComment;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+
+
+/** FLAC CUESHEET track index structure.  (See the
+ * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+       FLAC__uint64 offset;
+       /**< Offset in samples, relative to the track offset, of the index
+        * point.
+        */
+
+       FLAC__byte number;
+       /**< The index point number. */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+
+
+/** FLAC CUESHEET track structure.  (See the
+ * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+       FLAC__uint64 offset;
+       /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */
+
+       FLAC__byte number;
+       /**< The track number. */
+
+       char isrc[13];
+       /**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
+
+       unsigned type:1;
+       /**< The track type: 0 for audio, 1 for non-audio. */
+
+       unsigned pre_emphasis:1;
+       /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
+
+       FLAC__byte num_indices;
+       /**< The number of track index points. */
+
+       FLAC__StreamMetadata_CueSheet_Index *indices;
+       /**< NULL if num_indices == 0, else pointer to array of index points. */
+
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure.  (See the
+ * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+       char media_catalog_number[129];
+       /**< Media catalog number, in ASCII printable characters 0x20-0x7e.  In
+        * general, the media catalog number may be 0 to 128 bytes long; any
+        * unused characters should be right-padded with NUL characters.
+        */
+
+       FLAC__uint64 lead_in;
+       /**< The number of lead-in samples. */
+
+       FLAC__bool is_cd;
+       /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
+
+       unsigned num_tracks;
+       /**< The number of tracks. */
+
+       FLAC__StreamMetadata_CueSheet_Track *tracks;
+       /**< NULL if num_tracks == 0, else pointer to array of tracks. */
+
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+       FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+       FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ *  Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ *  will give the string equivalent.  The contents should not be
+ *  modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure.  (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+       FLAC__StreamMetadata_Picture_Type type;
+       /**< The kind of picture stored. */
+
+       char *mime_type;
+       /**< Picture data's MIME type, in ASCII printable characters
+        * 0x20-0x7e, NUL terminated.  For best compatibility with players,
+        * use picture data of MIME type \c image/jpeg or \c image/png.  A
+        * MIME type of '-->' is also allowed, in which case the picture
+        * data should be a complete URL.  In file storage, the MIME type is
+        * stored as a 32-bit length followed by the ASCII string with no NUL
+        * terminator, but is converted to a plain C string in this structure
+        * for convenience.
+        */
+
+       FLAC__byte *description;
+       /**< Picture's description in UTF-8, NUL terminated.  In file storage,
+        * the description is stored as a 32-bit length followed by the UTF-8
+        * string with no NUL terminator, but is converted to a plain C string
+        * in this structure for convenience.
+        */
+
+       FLAC__uint32 width;
+       /**< Picture's width in pixels. */
+
+       FLAC__uint32 height;
+       /**< Picture's height in pixels. */
+
+       FLAC__uint32 depth;
+       /**< Picture's color depth in bits-per-pixel. */
+
+       FLAC__uint32 colors;
+       /**< For indexed palettes (like GIF), picture's number of colors (the
+        * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth).
+        */
+
+       FLAC__uint32 data_length;
+       /**< Length of binary picture data in bytes. */
+
+       FLAC__byte *data;
+       /**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** Structure that is used when a metadata block of unknown type is loaded.
+ *  The contents are opaque.  The structure is used only internally to
+ *  correctly handle unknown metadata.
+ */
+typedef struct {
+       FLAC__byte *data;
+} FLAC__StreamMetadata_Unknown;
+
+
+/** FLAC metadata block structure.  (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+ */
+typedef struct {
+       FLAC__MetadataType type;
+       /**< The type of the metadata block; used determine which member of the
+        * \a data union to dereference.  If type >= FLAC__METADATA_TYPE_UNDEFINED
+        * then \a data.unknown must be used. */
+
+       FLAC__bool is_last;
+       /**< \c true if this metadata block is the last, else \a false */
+
+       unsigned length;
+       /**< Length, in bytes, of the block data as it appears in the stream. */
+
+       union {
+               FLAC__StreamMetadata_StreamInfo stream_info;
+               FLAC__StreamMetadata_Padding padding;
+               FLAC__StreamMetadata_Application application;
+               FLAC__StreamMetadata_SeekTable seek_table;
+               FLAC__StreamMetadata_VorbisComment vorbis_comment;
+               FLAC__StreamMetadata_CueSheet cue_sheet;
+               FLAC__StreamMetadata_Picture picture;
+               FLAC__StreamMetadata_Unknown unknown;
+       } data;
+       /**< Polymorphic block data; use the \a type value to determine which
+        * to use. */
+} FLAC__StreamMetadata;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+
+/** The total stream length of a metadata block header in bytes. */
+#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Utility functions
+ *
+ *****************************************************************************/
+
+/** Tests that a sample rate is valid for FLAC.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification, else
+ *    \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
+
+/** Tests that a sample rate is valid for the FLAC subset.  The subset rules
+ *  for valid sample rates are slightly more complex since the rate has to
+ *  be expressible completely in the frame header.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification for the
+ *    subset, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate);
+
+/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment names must be composed only of characters from
+ *  [0x20-0x3C,0x3E-0x7D].
+ *
+ * \param name       A NUL-terminated string to be checked.
+ * \assert
+ *    \code name != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name);
+
+/** Check a Vorbis comment entry value to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment values must be valid UTF-8 sequences.
+ *
+ * \param value      A string to be checked.
+ * \param length     A the length of \a value in bytes.  May be
+ *                   \c (unsigned)(-1) to indicate that \a value is a plain
+ *                   UTF-8 NUL-terminated string.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length);
+
+/** Check a Vorbis comment entry to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment entries must be of the form 'name=value', and 'name' and
+ *  'value' must be legal according to
+ *  FLAC__format_vorbiscomment_entry_name_is_legal() and
+ *  FLAC__format_vorbiscomment_entry_value_is_legal() respectively.
+ *
+ * \param entry      An entry to be checked.
+ * \param length     The length of \a entry in bytes.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length);
+
+/** Check a seek table to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seek table.
+ *
+ * \param seek_table  A pointer to a seek table to be checked.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Sort a seek table's seek points according to the format specification.
+ *  This includes a "unique-ification" step to remove duplicates, i.e.
+ *  seek points with identical \a sample_number values.  Duplicate seek
+ *  points are converted into placeholder points and sorted to the end of
+ *  the table.
+ *
+ * \param seek_table  A pointer to a seek table to be sorted.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval unsigned
+ *    The number of duplicate seek points converted into placeholders.
+ */
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param cue_sheet  A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Check picture data to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param picture    A pointer to existing picture data to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h
new file mode 100644 (file)
index 0000000..fff90b0
--- /dev/null
@@ -0,0 +1,2181 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__METADATA_H
+#define FLAC__METADATA_H
+
+#include <sys/types.h> /* for off_t */
+#include "export.h"
+#include "callback.h"
+#include "format.h"
+
+/* --------------------------------------------------------------------
+   (For an example of how all these routines are used, see the source
+   code for the unit tests in src/test_libFLAC/metadata_*.c, or
+   metaflac in src/metaflac/)
+   ------------------------------------------------------------------*/
+
+/** \file include/FLAC/metadata.h
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flac_metadata metadata \endlink module.
+ */
+
+/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in native FLAC files.
+ *  Note that currently only the Chain interface (level 2) supports Ogg
+ *  FLAC files, and it is read-only i.e. no writing back changed
+ *  metadata to file.
+ *
+ *  There are three metadata interfaces of increasing complexity:
+ *
+ *  Level 0:
+ *  Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ *  PICTURE blocks.
+ *
+ *  Level 1:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in most cases (more on this below), and uses less memory
+ *  than level 2.
+ *
+ *  Level 2:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in all cases, but uses more memory since all metadata for
+ *  the whole file is read into memory and manipulated before writing
+ *  out again.
+ *
+ *  What do we mean by efficient?  Since FLAC metadata appears at the
+ *  beginning of the file, when writing metadata back to a FLAC file
+ *  it is possible to grow or shrink the metadata such that the entire
+ *  file must be rewritten.  However, if the size remains the same during
+ *  changes or PADDING blocks are utilized, only the metadata needs to be
+ *  overwritten, which is much faster.
+ *
+ *  Efficient means the whole file is rewritten at most one time, and only
+ *  when necessary.  Level 1 is not efficient only in the case that you
+ *  cause more than one metadata block to grow or shrink beyond what can
+ *  be accomodated by padding.  In this case you should probably use level
+ *  2, which allows you to edit all the metadata for a file in memory and
+ *  write it out all at once.
+ *
+ *  All levels know how to skip over and not disturb an ID3v2 tag at the
+ *  front of the file.
+ *
+ *  All levels access files via their filenames.  In addition, level 2
+ *  has additional alternative read and write functions that take an I/O
+ *  handle and callbacks, for situations where access by filename is not
+ *  possible.
+ *
+ *  In addition to the three interfaces, this module defines functions for
+ *  creating and manipulating various metadata objects in memory.  As we see
+ *  from the Format module, FLAC metadata blocks in memory are very primitive
+ *  structures for storing information in an efficient way.  Reading
+ *  information from the structures is easy but creating or modifying them
+ *  directly is more complex.  The metadata object routines here facilitate
+ *  this by taking care of the consistency and memory management drudgery.
+ *
+ *  Unless you will be using the level 1 or 2 interfaces to modify existing
+ *  metadata however, you will not probably not need these.
+ *
+ *  From a dependency standpoint, none of the encoders or decoders require
+ *  the metadata module.  This is so that embedded users can strip out the
+ *  metadata module from libFLAC to reduce the size and complexity.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface
+ *  \ingroup flac_metadata
+ *
+ *  \brief
+ *  The level 0 interface consists of individual routines to read the
+ *  STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ *  only a filename.
+ *
+ *  They try to skip any ID3v2 tag at the head of the file.
+ *
+ * \{
+ */
+
+/** Read the STREAMINFO metadata block of the given FLAC file.  This function
+ *  will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param streaminfo  A pointer to space for the STREAMINFO block.  Since
+ *                    FLAC__StreamMetadata is a simple structure with no
+ *                    memory allocation involved, you pass the address of
+ *                    an existing structure.  It need not be initialized.
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid STREAMINFO block was read from \a filename.  Returns
+ *    \c false if there was a memory allocation error, a file decoder error,
+ *    or the file contained no STREAMINFO block.  (A memory allocation error
+ *    is possible because this function must set up a file decoder.)
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
+
+/** Read the VORBIS_COMMENT metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param tags        The address where the returned pointer will be
+ *                    stored.  The \a tags object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code tags != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid VORBIS_COMMENT block was read from \a filename,
+ *    and \a *tags will be set to the address of the metadata structure.
+ *    Returns \c false if there was a memory allocation error, a file
+ *    decoder error, or the file contained no VORBIS_COMMENT block, and
+ *    \a *tags will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
+
+/** Read the CUESHEET metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param cuesheet    The address where the returned pointer will be
+ *                    stored.  The \a cuesheet object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid CUESHEET block was read from \a filename,
+ *    and \a *cuesheet will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no CUESHEET
+ *    block, and \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
+/** Read a PICTURE metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *  Since there can be more than one PICTURE block in a file, this
+ *  function takes a number of parameters that act as constraints to
+ *  the search.  The PICTURE block with the largest area matching all
+ *  the constraints will be returned, or \a *picture will be set to
+ *  \c NULL if there was no such block.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param picture     The address where the returned pointer will be
+ *                    stored.  The \a picture object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \param type        The desired picture type.  Use \c -1 to mean
+ *                    "any type".
+ * \param mime_type   The desired MIME type, e.g. "image/jpeg".  The
+ *                    string will be matched exactly.  Use \c NULL to
+ *                    mean "any MIME type".
+ * \param description The desired description.  The string will be
+ *                    matched exactly.  Use \c NULL to mean "any
+ *                    description".
+ * \param max_width   The maximum width in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any width".
+ * \param max_height  The maximum height in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any height".
+ * \param max_depth   The maximum color depth in bits-per-pixel desired.
+ *                    Use \c (unsigned)(-1) to mean "any depth".
+ * \param max_colors  The maximum number of colors desired.  Use
+ *                    \c (unsigned)(-1) to mean "any number of colors".
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid PICTURE block was read from \a filename,
+ *    and \a *picture will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no PICTURE
+ *    block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 1 interface provides read-write access to FLAC file metadata and
+ * operates directly on the FLAC file.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create an iterator using FLAC__metadata_simple_iterator_new()
+ * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
+ *   the exit code.  Call FLAC__metadata_simple_iterator_is_writable() to
+ *   see if the file is writable, or only read access is allowed.
+ * - Use FLAC__metadata_simple_iterator_next() and
+ *   FLAC__metadata_simple_iterator_prev() to traverse the blocks.
+ *   This is does not read the actual blocks themselves.
+ *   FLAC__metadata_simple_iterator_next() is relatively fast.
+ *   FLAC__metadata_simple_iterator_prev() is slower since it needs to search
+ *   forward from the front of the file.
+ * - Use FLAC__metadata_simple_iterator_get_block_type() or
+ *   FLAC__metadata_simple_iterator_get_block() to access the actual data at
+ *   the current iterator position.  The returned object is yours to modify
+ *   and free.
+ * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block
+ *   back.  You must have write permission to the original file.  Make sure to
+ *   read the whole comment to FLAC__metadata_simple_iterator_set_block()
+ *   below.
+ * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks.
+ *   Use the object creation functions from
+ *   \link flac_metadata_object here \endlink to generate new objects.
+ * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block
+ *   currently referred to by the iterator, or replace it with padding.
+ * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when
+ *   finished.
+ *
+ * \note
+ * The FLAC file remains open the whole time between
+ * FLAC__metadata_simple_iterator_init() and
+ * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering
+ * the file during this time.
+ *
+ * \note
+ * Do not modify the \a is_last, \a length, or \a type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * If any of the modification functions
+ * (FLAC__metadata_simple_iterator_set_block(),
+ * FLAC__metadata_simple_iterator_delete_block(),
+ * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false,
+ * you should delete the iterator as it may no longer be valid.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_SimpleIterator;
+/** The opaque structure definition for the level 1 iterator type.
+ *  See the
+ *  \link flac_metadata_level1 metadata level 1 module \endlink
+ *  for a detailed description.
+ */
+typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator;
+
+/** Status type for FLAC__Metadata_SimpleIterator.
+ *
+ *  The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status().
+ */
+typedef enum {
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0,
+       /**< The iterator is in the normal OK state */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT,
+       /**< The data passed into a function violated the function's usage criteria */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE,
+       /**< The iterator could not open the target file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE,
+       /**< The iterator could not find the FLAC signature at the start of the file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE,
+       /**< The iterator tried to write to a file that was not writable */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA,
+       /**< The iterator encountered input that does not conform to the FLAC metadata specification */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR,
+       /**< The iterator encountered an error while reading the FLAC file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR,
+       /**< The iterator encountered an error while seeking in the FLAC file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR,
+       /**< The iterator encountered an error while writing the FLAC file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR,
+       /**< The iterator encountered an error renaming the FLAC file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR,
+       /**< The iterator encountered an error removing the temporary file */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
+       /**< Memory allocation failed */
+
+       FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
+       /**< The caller violated an assertion or an unexpected error occurred */
+
+} FLAC__Metadata_SimpleIteratorStatus;
+
+/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
+
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_SimpleIterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the current status of the iterator.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the status
+ *  to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__Metadata_SimpleIteratorStatus
+ *    The current status of the iterator.
+ */
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given FLAC file.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \param filename             The path to the FLAC file.
+ * \param read_only            If \c true, the FLAC file will be opened
+ *                             in read-only mode; if \c false, the FLAC
+ *                             file will be opened for edit even if no
+ *                             edits are performed.
+ * \param preserve_file_stats  If \c true, the owner and modification
+ *                             time will be preserved even if the FLAC
+ *                             file is written to.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if a memory allocation error occurs, the file can't be
+ *    opened, or another error occurs, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats);
+
+/** Returns \c true if the FLAC file is writable.  If \c false, calls to
+ *  FLAC__metadata_simple_iterator_set_block() and
+ *  FLAC__metadata_simple_iterator_insert_block_after() will fail.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Returns a flag telling if the current metadata block is the last.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if the current metadata block is the last in the file,
+ *    else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the offset of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval off_t
+ *    The offset of the metadata block at the current iterator position.
+ *    This is the byte offset relative to the beginning of the file of
+ *    the current metadata block's header.
+ */
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the type of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the length of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval unsigned
+ *    The length of the metadata block at the current iterator position.
+ *    The is same length as that in the
+ *    <a href="http://flac.sourceforge.net/format.html#metadata_block_header">metadata block header</a>,
+ *    i.e. the length of the metadata body that follows the header.
+ */
+FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the application ID of the \c APPLICATION block at the current
+ *  position.  This avoids reading the actual block data which can save
+ *  time for large blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param id        A pointer to a buffer of at least \c 4 bytes where
+ *                  the ID will be stored.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code id != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if the ID was successfully read, else \c false, in which
+ *    case you should check FLAC__metadata_simple_iterator_status() to
+ *    find out why.  If the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the
+ *    current metadata block is not an \c APPLICATION block.  Otherwise
+ *    if the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error
+ *    occurred and the iterator can no longer be used.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id);
+
+/** Get the metadata block at the current position.  You can modify the
+ *  block but must use FLAC__metadata_simple_iterator_set_block() to
+ *  write it back to the FLAC file.
+ *
+ *  You must call FLAC__metadata_object_delete() on the returned object
+ *  when you are finished with it.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block, or \c NULL if there was a memory
+ *    allocation error.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Write a block back to the FLAC file.  This function tries to be
+ *  as efficient as possible; how the block is actually written is
+ *  shown by the following:
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  STREAMINFO block: the new block is written in place.  Make sure
+ *  you know what you're doing when changing the values of a
+ *  STREAMINFO block.
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  not a STREAMINFO block: this is an error since the first block
+ *  must be a STREAMINFO block.  Returns \c false without altering the
+ *  file.
+ *
+ *  Existing block is not a STREAMINFO block and the new block is a
+ *  STREAMINFO block: this is an error since there may be only one
+ *  STREAMINFO block.  Returns \c false without altering the file.
+ *
+ *  Existing block and new block are the same length: the existing
+ *  block will be replaced by the new block, written in place.
+ *
+ *  Existing block is longer than new block: if use_padding is \c true,
+ *  the existing block will be overwritten in place with the new
+ *  block followed by a PADDING block, if possible, to make the total
+ *  size the same as the existing block.  Remember that a padding
+ *  block requires at least four bytes so if the difference in size
+ *  between the new block and existing block is less than that, the
+ *  entire file will have to be rewritten, using the new block's
+ *  exact size.  If use_padding is \c false, the entire file will be
+ *  rewritten, replacing the existing block by the new block.
+ *
+ *  Existing block is shorter than new block: if use_padding is \c true,
+ *  the function will try and expand the new block into the following
+ *  PADDING block, if it exists and doing so won't shrink the PADDING
+ *  block to less than 4 bytes.  If there is no following PADDING
+ *  block, or it will shrink to less than 4 bytes, or use_padding is
+ *  \c false, the entire file is rewritten, replacing the existing block
+ *  with the new block.  Note that in this case any following PADDING
+ *  block is preserved as is.
+ *
+ *  After writing the block, the iterator will remain in the same
+ *  place, i.e. pointing to the new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** This is similar to FLAC__metadata_simple_iterator_set_block()
+ *  except that instead of writing over an existing block, it appends
+ *  a block after the existing block.  \a use_padding is again used to
+ *  tell the function to try an expand into following padding in an
+ *  attempt to avoid rewriting the entire file.
+ *
+ *  This function will fail and return \c false if given a STREAMINFO
+ *  block.
+ *
+ *  After writing the block, the iterator will be pointing to the
+ *  new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** Deletes the block at the current position.  This will cause the
+ *  entire FLAC file to be rewritten, unless \a use_padding is \c true,
+ *  in which case the block will be replaced by an equal-sized PADDING
+ *  block.  The iterator will be left pointing to the block before the
+ *  one just deleted.
+ *
+ *  You may not delete the STREAMINFO block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 2 interface provides read-write access to FLAC file metadata;
+ * all metadata is read into memory, operated on in memory, and then written
+ * to file, which is more efficient than level 1 when editing multiple blocks.
+ *
+ * Currently Ogg FLAC is supported for read only, via
+ * FLAC__metadata_chain_read_ogg() but a subsequent
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create a new chain using FLAC__metadata_chain_new().  A chain is a
+ *   linked list of FLAC metadata blocks.
+ * - Read all metadata into the the chain from a FLAC file using
+ *   FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
+ *   check the status.
+ * - Optionally, consolidate the padding using
+ *   FLAC__metadata_chain_merge_padding() or
+ *   FLAC__metadata_chain_sort_padding().
+ * - Create a new iterator using FLAC__metadata_iterator_new()
+ * - Initialize the iterator to point to the first element in the chain
+ *   using FLAC__metadata_iterator_init()
+ * - Traverse the chain using FLAC__metadata_iterator_next and
+ *   FLAC__metadata_iterator_prev().
+ * - Get a block for reading or modification using
+ *   FLAC__metadata_iterator_get_block().  The pointer to the object
+ *   inside the chain is returned, so the block is yours to modify.
+ *   Changes will be reflected in the FLAC file when you write the
+ *   chain.  You can also add and delete blocks (see functions below).
+ * - When done, write out the chain using FLAC__metadata_chain_write().
+ *   Make sure to read the whole comment to the function below.
+ * - Delete the chain using FLAC__metadata_chain_delete().
+ *
+ * \note
+ * Even though the FLAC file is not open while the chain is being
+ * manipulated, you must not alter the file externally during
+ * this time.  The chain assumes the FLAC file will not change
+ * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg()
+ * and FLAC__metadata_chain_write().
+ *
+ * \note
+ * Do not modify the is_last, length, or type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * The metadata objects returned by FLAC__metadata_iterator_get_block()
+ * are owned by the chain; do not FLAC__metadata_object_delete() them.
+ * In the same way, blocks passed to FLAC__metadata_iterator_set_block()
+ * become owned by the chain and they will be deleted when the chain is
+ * deleted.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_Chain;
+/** The opaque structure definition for the level 2 chain type.
+ */
+typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain;
+
+struct FLAC__Metadata_Iterator;
+/** The opaque structure definition for the level 2 iterator type.
+ */
+typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator;
+
+typedef enum {
+       FLAC__METADATA_CHAIN_STATUS_OK = 0,
+       /**< The chain is in the normal OK state */
+
+       FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT,
+       /**< The data passed into a function violated the function's usage criteria */
+
+       FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE,
+       /**< The chain could not open the target file */
+
+       FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE,
+       /**< The chain could not find the FLAC signature at the start of the file */
+
+       FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE,
+       /**< The chain tried to write to a file that was not writable */
+
+       FLAC__METADATA_CHAIN_STATUS_BAD_METADATA,
+       /**< The chain encountered input that does not conform to the FLAC metadata specification */
+
+       FLAC__METADATA_CHAIN_STATUS_READ_ERROR,
+       /**< The chain encountered an error while reading the FLAC file */
+
+       FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR,
+       /**< The chain encountered an error while seeking in the FLAC file */
+
+       FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR,
+       /**< The chain encountered an error while writing the FLAC file */
+
+       FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR,
+       /**< The chain encountered an error renaming the FLAC file */
+
+       FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR,
+       /**< The chain encountered an error removing the temporary file */
+
+       FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
+       /**< Memory allocation failed */
+
+       FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR,
+       /**< The caller violated an assertion or an unexpected error occurred */
+
+       FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS,
+       /**< One or more of the required callbacks was NULL */
+
+       FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
+       /**< FLAC__metadata_chain_write() was called on a chain read by
+        *   FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+        *   or 
+        *   FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
+        *   was called on a chain read by
+        *   FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+        *   Matching read/write methods must always be used. */
+
+       FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL
+       /**< FLAC__metadata_chain_write_with_callbacks() was called when the
+        *   chain write requires a tempfile; use
+        *   FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead.
+        *   Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+        *   called when the chain write does not require a tempfile; use
+        *   FLAC__metadata_chain_write_with_callbacks() instead.
+        *   Always check FLAC__metadata_chain_check_if_tempfile_needed()
+        *   before writing via callbacks. */
+
+} FLAC__Metadata_ChainStatus;
+
+/** Maps a FLAC__Metadata_ChainStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_ChainStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
+
+/*********** FLAC__Metadata_Chain ***********/
+
+/** Create a new chain instance.
+ *
+ * \retval FLAC__Metadata_Chain*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
+
+/** Free a chain instance.  Deletes the object pointed to by \a chain.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
+
+/** Get the current status of the chain.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the
+ *  status to FLAC__METADATA_CHAIN_STATUS_OK.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__Metadata_ChainStatus
+ *    The current status of the chain.
+ */
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
+
+/** Read all metadata from a FLAC file into the chain.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the FLAC file to read.
+ * \assert
+ *    \code chain != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a filename, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the Ogg FLAC file to read.
+ * \assert
+ *    \code chain != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a filename, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from a FLAC stream into the chain via I/O callbacks.
+ *
+ *  The \a handle need only be open for reading, but must be seekable.
+ *  The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the FLAC stream to read.  The
+ *                 handle will NOT be closed after the metadata is read;
+ *                 that is the duty of the caller.
+ * \param callbacks
+ *                 A set of callbacks to use for I/O.  The mandatory
+ *                 callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a handle, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks.
+ *
+ *  The \a handle need only be open for reading, but must be seekable.
+ *  The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the Ogg FLAC stream to read.  The
+ *                 handle will NOT be closed after the metadata is read;
+ *                 that is the duty of the caller.
+ * \param callbacks
+ *                 A set of callbacks to use for I/O.  The mandatory
+ *                 callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a handle, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Checks if writing the given chain would require the use of a
+ *  temporary file, or if it could be written in place.
+ *
+ *  Under certain conditions, padding can be utilized so that writing
+ *  edited metadata back to the FLAC file does not require rewriting the
+ *  entire file.  If rewriting is required, then a temporary workfile is
+ *  required.  When writing metadata using callbacks, you must check
+ *  this function to know whether to call
+ *  FLAC__metadata_chain_write_with_callbacks() or
+ *  FLAC__metadata_chain_write_with_callbacks_and_tempfile().  When
+ *  writing with FLAC__metadata_chain_write(), the temporary file is
+ *  handled internally.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param use_padding
+ *                 Whether or not padding will be allowed to be used
+ *                 during the write.  The value of \a use_padding given
+ *                 here must match the value later passed to
+ *                 FLAC__metadata_chain_write_with_callbacks() or
+ *                 FLAC__metadata_chain_write_with_callbacks_with_tempfile().
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if writing the current chain would require a tempfile, or
+ *    \c false if metadata can be written in place.
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding);
+
+/** Write all metadata out to the FLAC file.  This function tries to be as
+ *  efficient as possible; how the metadata is actually written is shown by
+ *  the following:
+ *
+ *  If the current chain is the same size as the existing metadata, the new
+ *  data is written in place.
+ *
+ *  If the current chain is longer than the existing metadata, and
+ *  \a use_padding is \c true, and the last block is a PADDING block of
+ *  sufficient length, the function will truncate the final padding block
+ *  so that the overall size of the metadata is the same as the existing
+ *  metadata, and then just rewrite the metadata.  Otherwise, if not all of
+ *  the above conditions are met, the entire FLAC file must be rewritten.
+ *  If you want to use padding this way it is a good idea to call
+ *  FLAC__metadata_chain_sort_padding() first so that you have the maximum
+ *  amount of padding to work with, unless you need to preserve ordering
+ *  of the PADDING blocks for some reason.
+ *
+ *  If the current chain is shorter than the existing metadata, and
+ *  \a use_padding is \c true, and the final block is a PADDING block, the padding
+ *  is extended to make the overall size the same as the existing data.  If
+ *  \a use_padding is \c true and the last block is not a PADDING block, a new
+ *  PADDING block is added to the end of the new data to make it the same
+ *  size as the existing data (if possible, see the note to
+ *  FLAC__metadata_simple_iterator_set_block() about the four byte limit)
+ *  and the new data is written in place.  If none of the above apply or
+ *  \a use_padding is \c false, the entire FLAC file is rewritten.
+ *
+ *  If \a preserve_file_stats is \c true, the owner and modification time will
+ *  be preserved even if the FLAC file is written.
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks().
+ *
+ * \param chain               A pointer to an existing chain.
+ * \param use_padding         See above.
+ * \param preserve_file_stats See above.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  The \a handle must be open for updating and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b"
+ *  for Windows).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c false.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O.  The mandatory
+ *                     callbacks are \a write and \a seek.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  This version of the write-with-callbacks function must be used when
+ *  FLAC__metadata_chain_check_if_tempfile_needed() returns true.  In
+ *  this function, you must supply an I/O handle corresponding to the
+ *  FLAC file to edit, and a temporary handle to which the new FLAC
+ *  file will be written.  It is the caller's job to move this temporary
+ *  FLAC file on top of the original FLAC file to complete the metadata
+ *  edit.
+ *
+ *  The \a handle must be open for reading and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ *  The \a temp_handle must be open for writing.  The
+ *  equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb"
+ *  for Windows).  It should be an empty stream, or at least positioned
+ *  at the start-of-file (in which case it is the caller's duty to
+ *  truncate it on return).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c true.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the original FLAC stream to read.
+ *                     The handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O on \a handle.
+ *                     The mandatory callbacks are \a read, \a seek, and
+ *                     \a eof.
+ * \param temp_handle  The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param temp_callbacks
+ *                     A set of callbacks to use for I/O on temp_handle.
+ *                     The only mandatory callback is \a write.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks);
+
+/** Merge adjacent PADDING blocks into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain               A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+
+/** This function will move all PADDING blocks to the end on the metadata,
+ *  then merge them into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+
+/*********** FLAC__Metadata_Iterator ***********/
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_Iterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given chain.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \param chain     A pointer to an existing and initialized (read) chain.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator);
+
+/** Get the type of the metadata block at the current position.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator);
+
+/** Get the metadata block at the current position.  You can modify
+ *  the block in place but must write the chain before the changes
+ *  are reflected to the FLAC file.  You do not need to call
+ *  FLAC__metadata_iterator_set_block() to reflect the changes;
+ *  the pointer returned by FLAC__metadata_iterator_get_block()
+ *  points directly into the chain.
+ *
+ * \warning
+ * Do not call FLAC__metadata_object_delete() on the returned object;
+ * to delete a block use FLAC__metadata_iterator_delete_block().
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator);
+
+/** Set the metadata block at the current position, replacing the existing
+ *  block.  The new block passed in becomes owned by the chain and it will be
+ *  deleted when the chain is deleted.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Removes the current block from the chain.  If \a replace_with_padding is
+ *  \c true, the block will instead be replaced with a padding block of equal
+ *  size.  You can not delete the STREAMINFO block.  The iterator will be
+ *  left pointing to the block before the one just "deleted", even if
+ *  \a replace_with_padding is \c true.
+ *
+ * \param iterator              A pointer to an existing initialized iterator.
+ * \param replace_with_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met,
+ *    otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding);
+
+/** Insert a new block before the current block.  You cannot insert a block
+ *  before the first STREAMINFO block.  You cannot insert a STREAMINFO block
+ *  as there can be only one, the one that already exists at the head when you
+ *  read in a chain.  The chain takes ownership of the new block and it will be
+ *  deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Insert a new block after the current block.  You cannot insert a STREAMINFO
+ *  block as there can be only one, the one that already exists at the head when
+ *  you read in a chain.  The chain takes ownership of the new block and it will
+ *  be deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * This module contains methods for manipulating FLAC metadata objects.
+ *
+ * Since many are variable length we have to be careful about the memory
+ * management.  We decree that all pointers to data in the object are
+ * owned by the object and memory-managed by the object.
+ *
+ * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete()
+ * functions to create all instances.  When using the
+ * FLAC__metadata_object_set_*() functions to set pointers to data, set
+ * \a copy to \c true to have the function make it's own copy of the data, or
+ * to \c false to give the object ownership of your data.  In the latter case
+ * your pointer must be freeable by free() and will be free()d when the object
+ * is FLAC__metadata_object_delete()d.  It is legal to pass a null pointer as
+ * the data pointer to a FLAC__metadata_object_set_*() function as long as
+ * the length argument is 0 and the \a copy argument is \c false.
+ *
+ * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function
+ * will return \c NULL in the case of a memory allocation error, otherwise a new
+ * object.  The FLAC__metadata_object_set_*() functions return \c false in the
+ * case of a memory allocation error.
+ *
+ * We don't have the convenience of C++ here, so note that the library relies
+ * on you to keep the types straight.  In other words, if you pass, for
+ * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to
+ * FLAC__metadata_object_application_set_data(), you will get an assertion
+ * failure.
+ *
+ * For convenience the FLAC__metadata_object_vorbiscomment_*() functions
+ * maintain a trailing NUL on each Vorbis comment entry.  This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
+ * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis
+ * comment entry/name/value will first validate that it complies with the Vorbis
+ * comment specification and return false if it does not.
+ *
+ * There is no need to recalculate the length field on metadata blocks you
+ * have modified.  They will be calculated automatically before they  are
+ * written back to a file.
+ *
+ * \{
+ */
+
+
+/** Create a new metadata object instance of the given type.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0,
+ *  with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ *  the vendor string set (but zero comments).
+ *
+ *  Do not pass in a value greater than or equal to
+ *  \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're
+ *  doing.
+ *
+ * \param type  Type of object to create
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory or the type code is
+ *    greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type);
+
+/** Create a copy of an existing metadata object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new block and
+ *  is responsible for freeing it with FLAC__metadata_object_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object);
+
+/** Free a metadata object.  Deletes the object pointed to by \a object.
+ *
+ *  The delete is a "deep" delete, i.e. dynamically allocated data within the
+ *  object is also deleted.
+ *
+ * \param object  A pointer to an existing object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object);
+
+/** Compares two metadata objects.
+ *
+ *  The compare is "deep", i.e. dynamically allocated data within the
+ *  object is also compared.
+ *
+ * \param block1  A pointer to an existing object.
+ * \param block2  A pointer to an existing object.
+ * \assert
+ *    \code block1 != NULL \endcode
+ *    \code block2 != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if objects are identical, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2);
+
+/** Sets the application data of an APPLICATION block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing data will be freed if this
+ *  function is successful, otherwise the original data will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing APPLICATION object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
+
+/** Resize the seekpoint array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new placeholder
+ *  points will be added to the end.
+ *
+ * \param object          A pointer to an existing SEEKTABLE object.
+ * \param new_num_points  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) ||
+ * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
+
+/** Set a seekpoint in a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ */
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Insert a seekpoint into a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points >= point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Delete a seekpoint from a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
+
+/** Check a seektable to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seektable.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object);
+
+/** Append a number of placeholder points to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
+
+/** Append a specific seek point template to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_number  The sample number of the seek point template.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number);
+
+/** Append specific seek point templates to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_numbers  An array of sample numbers for the seek points.
+ * \param num     The number of seek point templates to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ *  seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced approximately
+ *                       \a total_samples / \a num samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ *  seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param samples The number of samples apart to space the placeholder
+ *                points.  The first point will be at sample \c 0, the
+ *                second at sample \a samples, then 2*\a samples, and
+ *                so on.  As long as \a samples and \a total_samples
+ *                are greater than \c 0, there will always be at least
+ *                one seekpoint at sample \c 0.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced
+ *                       \a samples samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code samples > 0 \endcode
+ *    \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples);
+
+/** Sort a seek table's seek points according to the format specification,
+ *  removing duplicates.
+ *
+ * \param object   A pointer to a seek table to be sorted.
+ * \param compact  If \c false, behaves like FLAC__format_seektable_sort().
+ *                 If \c true, duplicates are deleted and the seek table is
+ *                 shrunk appropriately; the number of placeholder points
+ *                 present in the seek table will be the same after the call
+ *                 as before.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
+
+/** Sets the vendor string in a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object  A pointer to an existing VORBIS_COMMENT object.
+ * \param entry   The entry to set the vendor string to.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Resize the comment array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new empty
+ *  fields will be added to the end.
+ *
+ * \param object            A pointer to an existing VORBIS_COMMENT object.
+ * \param new_num_comments  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) ||
+ * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments);
+
+/** Sets a comment in a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  Index into comment array to set.
+ * \param entry        The entry to set the comment to.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code comment_num < object->data.vorbis_comment.num_comments \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Insert a comment in a VORBIS_COMMENT block at the given index.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index at which to insert the comment.  The comments
+ *                     at and after \a comment_num move right one position.
+ *                     To append a comment to the end, set \a comment_num to
+ *                     \c object->data.vorbis_comment.num_comments .
+ * \param entry        The comment to insert.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments >= comment_num \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param entry        The comment to insert.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  Depending on the the value of \a all, either all or just the first comment
+ *  whose field name(s) match the given entry's name will be replaced by the
+ *  given entry.  If no comments match, \a entry will simply be appended.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param entry        The comment to insert.
+ * \param all          If \c true, all comments whose field name matches
+ *                     \a entry's field name will be removed, and \a entry will
+ *                     be inserted at the position of the first matching
+ *                     comment.  If \c false, only the first comment whose
+ *                     field name matches \a entry's field name will be
+ *                     replaced with \a entry.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy);
+
+/** Delete a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index of the comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments > comment_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
+
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ *  On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ *  memory and shall be owned by the caller.  For convenience the entry will
+ *  have a terminating NUL.
+ *
+ * \param entry              A pointer to a Vorbis comment entry.  The entry's
+ *                           \c entry pointer should not point to allocated
+ *                           memory as it will be overwritten.
+ * \param field_name         The field name in ASCII, \c NUL terminated.
+ * \param field_value        The field value in UTF-8, \c NUL terminated.
+ * \assert
+ *    \code entry != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if malloc() fails, or if \a field_name or \a field_value does
+ *    not comply with the Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ *  The returned pointers to name and value will be allocated by malloc()
+ *  and shall be owned by the caller.
+ *
+ * \param entry              An existing Vorbis comment entry.
+ * \param field_name         The address of where the returned pointer to the
+ *                           field name will be stored.
+ * \param field_value        The address of where the returned pointer to the
+ *                           field value will be stored.
+ * \assert
+ *    \code (entry.entry != NULL && entry.length > 0) \endcode
+ *    \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
+/** Check if the given Vorbis comment entry's field name matches the given
+ *  field name.
+ *
+ * \param entry              An existing Vorbis comment entry.
+ * \param field_name         The field name to check.
+ * \param field_name_length  The length of \a field_name, not including the
+ *                           terminating \c NUL.
+ * \assert
+ *    \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \retval FLAC__bool
+ *    \c true if the field names match, else \c false
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length);
+
+/** Find a Vorbis comment with the given field name.
+ *
+ *  The search begins at entry number \a offset; use an offset of 0 to
+ *  search from the beginning of the comment array.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param offset      The offset into the comment array from where to start
+ *                    the search.
+ * \param field_name  The field name of the comment to find.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code field_name != NULL \endcode
+ * \retval int
+ *    The offset in the comment array of the first comment whose field
+ *    name matches \a field_name, or \c -1 if no match was found.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comments to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Create a new CUESHEET track instance.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
+
+/** Create a copy of an existing CUESHEET track object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new object and
+ *  is responsible for freeing it with
+ *  FLAC__metadata_object_cuesheet_track_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Delete a CUESHEET track object
+ *
+ * \param object       A pointer to an existing CUESHEET track object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Resize a track's index point array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  indices will be added to the end.
+ *
+ * \param object           A pointer to an existing CUESHEET object.
+ * \param track_num        The index of the track to modify.  NOTE: this is not
+ *                         necessarily the same as the track's \a number field.
+ * \param new_num_indices  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) ||
+ * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+
+/** Insert an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \param index        The index point to insert.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/** Insert a blank index point in a CUESHEET track at the given index.
+ *
+ *  A blank index point is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Delete an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     modify.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \param index_num    The index into the track's index array of the index
+ *                     to delete.  NOTE: this is not necessarily the same
+ *                     as the index's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Resize the track array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  tracks will be added to the end.
+ *
+ * \param object            A pointer to an existing CUESHEET object.
+ * \param new_num_tracks    The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) ||
+ * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+
+/** Sets a track in a CUESHEET block.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    Index into track array to set.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param track        The track to set the track to.  You may safely pass in
+ *                     a const pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code track_num < object->data.cue_sheet.num_tracks \endcode
+ *    \code (track->indices != NULL && track->num_indices > 0) ||
+ * (track->indices == NULL && track->num_indices == 0)
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a track in a CUESHEET block at the given index.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \param track        The track to insert.  You may safely pass in a const
+ *                     pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a blank track in a CUESHEET block at the given index.
+ *
+ *  A blank track is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Delete a track in a CUESHEET block at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     delete.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Calculate and return the CDDB/freedb ID for a cue sheet.  The function
+ *  assumes the cue sheet corresponds to a CD; the result is undefined
+ *  if the cuesheet's is_cd bit is not set.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ *    The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
+/** Sets the MIME type of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param mime_type   A pointer to the MIME type string.  The string must be
+ *                    ASCII characters 0x20-0x7e, NUL-terminated.  No validation
+ *                    is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (mime_type != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string.  The string must be
+ *                    valid UTF-8, NUL-terminated.  No validation is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (description != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  Also sets the \a data_length field of the
+ *  metadata object to what is passed in as the \a length parameter.  The
+ *  existing data will be freed if this function is successful, otherwise the
+ *  original data and data_length will remain if \a copy is \c true and
+ *  malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing PICTURE object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param object     A pointer to existing PICTURE block to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \retval FLAC__bool
+ *    \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/FLAC/ordinals.h b/include/FLAC/ordinals.h
new file mode 100644 (file)
index 0000000..a7a5cd9
--- /dev/null
@@ -0,0 +1,80 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ORDINALS_H
+#define FLAC__ORDINALS_H
+
+#if !(defined(_MSC_VER) || defined(__BORLANDC__) || defined(__EMX__))
+#include <inttypes.h>
+#endif
+
+typedef signed char FLAC__int8;
+typedef unsigned char FLAC__uint8;
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int16 FLAC__int16;
+typedef __int32 FLAC__int32;
+typedef __int64 FLAC__int64;
+typedef unsigned __int16 FLAC__uint16;
+typedef unsigned __int32 FLAC__uint32;
+typedef unsigned __int64 FLAC__uint64;
+#elif defined(__EMX__)
+typedef short FLAC__int16;
+typedef long FLAC__int32;
+typedef long long FLAC__int64;
+typedef unsigned short FLAC__uint16;
+typedef unsigned long FLAC__uint32;
+typedef unsigned long long FLAC__uint64;
+#else
+typedef int16_t FLAC__int16;
+typedef int32_t FLAC__int32;
+typedef int64_t FLAC__int64;
+typedef uint16_t FLAC__uint16;
+typedef uint32_t FLAC__uint32;
+typedef uint64_t FLAC__uint64;
+#endif
+
+typedef int FLAC__bool;
+
+typedef FLAC__uint8 FLAC__byte;
+
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#ifndef __cplusplus
+#define true 1
+#define false 0
+#endif
+
+#endif
diff --git a/include/FLAC/stream_decoder.h b/include/FLAC/stream_decoder.h
new file mode 100644 (file)
index 0000000..9ac1594
--- /dev/null
@@ -0,0 +1,1559 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_DECODER_H
+#define FLAC__STREAM_DECODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_decoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module describes the decoder layers provided by libFLAC.
+ *
+ * The stream decoder can be used to decode complete streams either from
+ * the client via callbacks, or directly from a file, depending on how
+ * it is initialized.  When decoding via callbacks, the client provides
+ * callbacks for reading FLAC data and writing decoded samples, and
+ * handling metadata and errors.  If the client also supplies seek-related
+ * callback, the decoder function for sample-accurate seeking within the
+ * FLAC input is also available.  When decoding from a file, the client
+ * needs only supply a filename or open \c FILE* and write/metadata/error
+ * callbacks; the rest of the callbacks are supplied internally.  For more
+ * info see the \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
+ *  \ingroup flac_decoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ * The stream decoder can decode native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ *   FLAC__stream_decoder_new().
+ * - The program overrides the default settings using
+ *   FLAC__stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for decoding using
+ *   - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE()
+ *     or FLAC__stream_decoder_init_file() for native FLAC,
+ *   - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE()
+ *     or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC
+ * - The program calls the FLAC__stream_decoder_process_*() functions
+ *   to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__stream_decoder_finish(),
+ *   which flushes the input and output and resets the decoder to the
+ *   uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__stream_decoder_delete().
+ *
+ * In more detail, the program will create a new instance by calling
+ * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*()
+ * functions to override the default decoder options, and call
+ * one of the FLAC__stream_decoder_init_*() functions.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the decoder to decode FLAC data from the client via
+ * callbacks, and two for decoding directly from a FLAC file.
+ *
+ * For decoding via callbacks, use FLAC__stream_decoder_init_stream().
+ * You must also supply several callbacks for handling I/O.  Some (like
+ * seeking) are optional, depending on the capabilities of the input.
+ *
+ * For decoding directly from a file, use FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file().  Then you must only supply an open
+ * \c FILE* or filename and fewer callbacks; the decoder will handle
+ * the other callbacks internally.
+ *
+ * There are three similarly-named init functions for decoding from Ogg
+ * FLAC streams.  Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * Once the decoder is initialized, your program will call one of several
+ * functions to start the decoding process:
+ *
+ * - FLAC__stream_decoder_process_single() - Tells the decoder to process at
+ *   most one metadata block or audio frame and return, calling either the
+ *   metadata callback or write callback, respectively, once.  If the decoder
+ *   loses sync it will return with only the error callback being called.
+ * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder
+ *   to process the stream from the current location and stop upon reaching
+ *   the first audio frame.  The client will get one metadata, write, or error
+ *   callback per metadata block, audio frame, or sync error, respectively.
+ * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder
+ *   to process the stream from the current location until the read callback
+ *   returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or
+ *   FLAC__STREAM_DECODER_READ_STATUS_ABORT.  The client will get one metadata,
+ *   write, or error callback per metadata block, audio frame, or sync error,
+ *   respectively.
+ *
+ * When the decoder has finished decoding (normally or through an abort),
+ * the instance is finished by calling FLAC__stream_decoder_finish(), which
+ * ensures the decoder is in the correct state and frees memory.  Then the
+ * instance may be deleted with FLAC__stream_decoder_delete() or initialized
+ * again to decode another stream.
+ *
+ * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method.
+ * At any point after the stream decoder has been initialized, the client can
+ * call this function to seek to an exact sample within the stream.
+ * Subsequently, the first time the write callback is called it will be
+ * passed a (possibly partial) block starting at that sample.
+ *
+ * If the client cannot seek via the callback interface provided, but still
+ * has another way of seeking, it can flush the decoder using
+ * FLAC__stream_decoder_flush() and start feeding data from the new position
+ * through the read callback.
+ *
+ * The stream decoder also provides MD5 signature checking.  If this is
+ * turned on before initialization, FLAC__stream_decoder_finish() will
+ * report when the decoded MD5 signature does not match the one stored
+ * in the STREAMINFO block.  MD5 checking is automatically turned off
+ * (until the next FLAC__stream_decoder_reset()) if there is no signature
+ * in the STREAMINFO block or when a seek is attempted.
+ *
+ * The FLAC__stream_decoder_set_metadata_*() functions deserve special
+ * attention.  By default, the decoder only calls the metadata_callback for
+ * the STREAMINFO block.  These functions allow you to tell the decoder
+ * explicitly which blocks to parse and return via the metadata_callback
+ * and/or which to skip.  Use a FLAC__stream_decoder_set_metadata_respond_all(),
+ * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(),
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify
+ * which blocks to return.  Remember that metadata blocks can potentially
+ * be big (for example, cover art) so filtering out the ones you don't
+ * use can reduce the memory requirements of the decoder.  Also note the
+ * special forms FLAC__stream_decoder_set_metadata_respond_application(id)
+ * and FLAC__stream_decoder_set_metadata_ignore_application(id) for
+ * filtering APPLICATION blocks based on the application ID.
+ *
+ * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
+ * they still can legally be filtered from the metadata_callback.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
+ * before FLAC__stream_decoder_init_*().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamDecoder
+ *
+ * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0,
+       /**< The decoder is ready to search for metadata. */
+
+       FLAC__STREAM_DECODER_READ_METADATA,
+       /**< The decoder is ready to or is in the process of reading metadata. */
+
+       FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC,
+       /**< The decoder is ready to or is in the process of searching for the
+        * frame sync code.
+        */
+
+       FLAC__STREAM_DECODER_READ_FRAME,
+       /**< The decoder is ready to or is in the process of reading a frame. */
+
+       FLAC__STREAM_DECODER_END_OF_STREAM,
+       /**< The decoder has reached the end of the stream. */
+
+       FLAC__STREAM_DECODER_OGG_ERROR,
+       /**< An error occurred in the underlying Ogg layer.  */
+
+       FLAC__STREAM_DECODER_SEEK_ERROR,
+       /**< An error occurred while seeking.  The decoder must be flushed
+        * with FLAC__stream_decoder_flush() or reset with
+        * FLAC__stream_decoder_reset() before decoding can continue.
+        */
+
+       FLAC__STREAM_DECODER_ABORTED,
+       /**< The decoder was aborted by the read callback. */
+
+       FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+       /**< An error occurred allocating memory.  The decoder is in an invalid
+        * state and can no longer be used.
+        */
+
+       FLAC__STREAM_DECODER_UNINITIALIZED
+       /**< The decoder is in the uninitialized state; one of the
+        * FLAC__stream_decoder_init_*() functions must be called before samples
+        * can be processed.
+        */
+
+} FLAC__StreamDecoderState;
+
+/** Maps a FLAC__StreamDecoderState to a C string.
+ *
+ *  Using a FLAC__StreamDecoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_decoder_init_*() functions.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
+       /**< Initialization was successful. */
+
+       FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+       /**< The library was not compiled with support for the given container
+        * format.
+        */
+
+       FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
+       /**< A required callback was not supplied. */
+
+       FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
+       /**< An error occurred allocating memory. */
+
+       FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
+       /**< fopen() failed in FLAC__stream_decoder_init_file() or
+        * FLAC__stream_decoder_init_ogg_file(). */
+
+       FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
+       /**< FLAC__stream_decoder_init_*() was called when the decoder was
+        * already initialized, usually because
+        * FLAC__stream_decoder_finish() was not called.
+        */
+
+} FLAC__StreamDecoderInitStatus;
+
+/** Maps a FLAC__StreamDecoderInitStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderInitStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder read callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
+       /**< The read was OK and decoding can continue. */
+
+       FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
+       /**< The read was attempted while at the end of the stream.  Note that
+        * the client must only return this value when the read callback was
+        * called when already at the end of the stream.  Otherwise, if the read
+        * itself moves to the end of the stream, the client should still return
+        * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on
+        * the next read callback it should return
+        * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count
+        * of \c 0.
+        */
+
+       FLAC__STREAM_DECODER_READ_STATUS_ABORT
+       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderReadStatus;
+
+/** Maps a FLAC__StreamDecoderReadStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderReadStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder seek callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_SEEK_STATUS_OK,
+       /**< The seek was OK and decoding can continue. */
+
+       FLAC__STREAM_DECODER_SEEK_STATUS_ERROR,
+       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+       FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+       /**< Client does not support seeking. */
+
+} FLAC__StreamDecoderSeekStatus;
+
+/** Maps a FLAC__StreamDecoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder tell callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_TELL_STATUS_OK,
+       /**< The tell was OK and decoding can continue. */
+
+       FLAC__STREAM_DECODER_TELL_STATUS_ERROR,
+       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+       FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+       /**< Client does not support telling the position. */
+
+} FLAC__StreamDecoderTellStatus;
+
+/** Maps a FLAC__StreamDecoderTellStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder length callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_LENGTH_STATUS_OK,
+       /**< The length call was OK and decoding can continue. */
+
+       FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR,
+       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+       FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+       /**< Client does not support reporting the length. */
+
+} FLAC__StreamDecoderLengthStatus;
+
+/** Maps a FLAC__StreamDecoderLengthStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderLengthStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder write callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
+       /**< The write was OK and decoding can continue. */
+
+       FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
+       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderWriteStatus;
+
+/** Maps a FLAC__StreamDecoderWriteStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderWriteStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
+
+
+/** Possible values passed back to the FLAC__StreamDecoder error callback.
+ *  \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch-
+ *  all.  The rest could be caused by bad sync (false synchronization on
+ *  data that is not the start of a frame) or corrupted data.  The error
+ *  itself is the decoder's best guess at what happened assuming a correct
+ *  sync.  For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER
+ *  could be caused by a correct sync on the start of a frame, but some
+ *  data in the frame header was corrupted.  Or it could be the result of
+ *  syncing on a point the stream that looked like the starting of a frame
+ *  but was not.  \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ *  could be because the decoder encountered a valid frame made by a future
+ *  version of the encoder which it cannot parse, or because of a false
+ *  sync making it appear as though an encountered frame was generated by
+ *  a future encoder.
+ */
+typedef enum {
+
+       FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
+       /**< An error in the stream caused the decoder to lose synchronization. */
+
+       FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
+       /**< The decoder encountered a corrupted frame header. */
+
+       FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
+       /**< The frame's data did not match the CRC in the footer. */
+
+       FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+       /**< The decoder encountered reserved fields in use in the stream. */
+
+} FLAC__StreamDecoderErrorStatus;
+
+/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderErrorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamDecoderProtected;
+struct FLAC__StreamDecoderPrivate;
+/** The opaque structure definition for the stream decoder type.
+ *  See the \link flac_stream_decoder stream decoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+       struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+       struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamDecoder;
+
+/** Signature for the read callback.
+ *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_decoder_init*_stream(). The supplied function will be
+ *  called when the decoder needs more input data.  The address of the
+ *  buffer to be filled is supplied, along with the number of bytes the
+ *  buffer can hold.  The callback may choose to supply less data and
+ *  modify the byte count but must be careful not to overflow the buffer.
+ *  The callback then returns a status code chosen from
+ *  FLAC__StreamDecoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(*bytes > 0) {
+ *     *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ *     if(ferror(file))
+ *       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ *     else if(*bytes == 0)
+ *       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ *     else
+ *       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ *   }
+ *   else
+ *     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be decoded.
+ * \param  bytes    A pointer to the size of the buffer.  On entry
+ *                  to the callback, it contains the maximum number
+ *                  of bytes that may be stored in \a buffer.  The
+ *                  callee must set it to the actual number of bytes
+ *                  stored (0 in case of error or end-of-stream) before
+ *                  returning.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderReadStatus
+ *    The callee's return status.  Note that the callback should return
+ *    \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
+ *    zero bytes were read and there is no more data to be read.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder needs to seek the input stream.  The decoder
+ *  will pass the absolute byte offset to seek to, 0 meaning the
+ *  beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ *   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ *   else
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder wants to know the current position of the
+ *  stream.  The callback should return the byte offset from the
+ *  beginning of the stream.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   off_t pos;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ *   else if((pos = ftello(file)) < 0)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ *   else {
+ *     *absolute_byte_offset = (FLAC__uint64)pos;
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  A pointer to storage for the current offset
+ *                               from the beginning of the stream.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder wants to know the total length of the stream
+ *  in bytes.
+ *
+ * Here is an example of a length callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   struct stat filestats;
+ *
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ *   else if(fstat(fileno(file), &filestats) != 0)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ *   else {
+ *     *stream_length = (FLAC__uint64)filestats.st_size;
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  stream_length  A pointer to storage for the length of the stream
+ *                        in bytes.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderLengthStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder needs to know if the end of the stream has
+ *  been reached.
+ *
+ * Here is an example of a EOF callback for stdio streams:
+ * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
+ * \code
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   return feof(file)? true : false;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__bool
+ *    \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/** Signature for the write callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  single audio frame.  The decoder will pass the frame metadata as well
+ *  as an array of pointers (one for each channel) pointing to the
+ *  decoded audio.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  frame    The description of the decoded frame.  See
+ *                  FLAC__Frame.
+ * \param  buffer   An array of pointers to decoded channels of data.
+ *                  Each pointer will point to an array of signed
+ *                  samples of length \a frame->header.blocksize.
+ *                  Channels will be ordered according to the FLAC
+ *                  specification; see the documentation for the
+ *                  <A HREF="../format.html#frame_header">frame header</A>.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  metadata block.  In a valid FLAC file there will always be one
+ *  \c STREAMINFO block, followed by zero or more other metadata blocks.
+ *  These will be supplied by the decoder in the same order as they
+ *  appear in the stream and always before the first audio frame (i.e.
+ *  write callback).  The metadata block that is passed in must not be
+ *  modified, and it doesn't live beyond the callback, so you should make
+ *  a copy of it with FLAC__metadata_object_clone() if you will need it
+ *  elsewhere.  Since metadata blocks can potentially be large, by
+ *  default the decoder only calls the metadata callback for the
+ *  \c STREAMINFO block; you can instruct the decoder to pass or filter
+ *  other blocks with FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  metadata The decoded metadata block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called whenever an error occurs during
+ *  decoding.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  status   The error encountered by the decoder.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream decoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__stream_decoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__StreamDecoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void);
+
+/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder  A pointer to an existing decoder.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream within the Ogg container.
+ *  The default behavior is to use the serial number of the first Ogg
+ *  page.  Setting a serial number here will explicitly specify which
+ *  stream is to be decoded.
+ *
+ * \note
+ * This does not need to be set for native FLAC decoding.
+ *
+ * \default \c use serial number of first page
+ * \param  decoder        A decoder instance to set.
+ * \param  serial_number  See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
+
+/** Set the "MD5 signature checking" flag.  If \c true, the decoder will
+ *  compute the MD5 signature of the unencoded audio data while decoding
+ *  and compare it to the signature from the STREAMINFO block, if it
+ *  exists, during FLAC__stream_decoder_finish().
+ *
+ *  MD5 signature checking will be turned off (until the next
+ *  FLAC__stream_decoder_reset()) if there is no signature in the
+ *  STREAMINFO block or when a seek is attempted.
+ *
+ *  Clients that do not use the MD5 check should leave this off to speed
+ *  up decoding.
+ *
+ * \default \c false
+ * \param  decoder  A decoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value);
+
+/** Direct the decoder to pass on all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to pass on all APPLICATION metadata blocks of the
+ *  given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to pass on all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
+
+/** Direct the decoder to filter out all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to filter out all APPLICATION metadata blocks of
+ *  the given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to filter out all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The current decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval const char *
+ *    The decoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ *  This is the value of the setting, not whether or not the decoder is
+ *  currently checking the MD5 (remember, it can be turned off automatically
+ *  by a seek).  When the decoder is reset the flag will be restored to the
+ *  value returned by this function.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder);
+
+/** Get the total number of samples in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the \c STREAMINFO block.  A value of \c 0 means "unknown".
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
+
+/** Get the current number of channels in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+
+/** Get the current channel assignment in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ *    See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample resolution in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample rate in Hz of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+
+/** Get the current blocksize of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+
+/** Returns the decoder's current read position within the stream.
+ *  The position is the byte offset from the start of the stream.
+ *  Bytes before this position have been fully decoded.  Note that
+ *  there may still be undecoded bytes in the decoder's read FIFO.
+ *  The returned position is correct even after a seek.
+ *
+ *  \warning This function currently only works for native FLAC,
+ *           not Ogg FLAC streams.
+ *
+ * \param  decoder   A decoder instance to query.
+ * \param  position  Address at which to return the desired position.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code position != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, \c false if the stream is not native FLAC,
+ *    or there was an error from the 'tell' callback or it returned
+ *    \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance to decode native FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  native FLAC stream. I/O is performed via callbacks to the client.
+ *  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+       FLAC__StreamDecoder *decoder,
+       FLAC__StreamDecoderReadCallback read_callback,
+       FLAC__StreamDecoderSeekCallback seek_callback,
+       FLAC__StreamDecoderTellCallback tell_callback,
+       FLAC__StreamDecoderLengthCallback length_callback,
+       FLAC__StreamDecoderEofCallback eof_callback,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  FLAC stream in an Ogg container. I/O is performed via callbacks to the
+ *  client.  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+       FLAC__StreamDecoder *decoder,
+       FLAC__StreamDecoderReadCallback read_callback,
+       FLAC__StreamDecoderSeekCallback seek_callback,
+       FLAC__StreamDecoderTellCallback tell_callback,
+       FLAC__StreamDecoderLengthCallback length_callback,
+       FLAC__StreamDecoderEofCallback eof_callback,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain native FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdout since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+       FLAC__StreamDecoder *decoder,
+       FILE *file,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain Ogg FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdout since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+       FLAC__StreamDecoder *decoder,
+       FILE *file,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  native FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+       FLAC__StreamDecoder *decoder,
+       const char *filename,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+       FLAC__StreamDecoder *decoder,
+       const char *filename,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+);
+
+/** Finish the decoding process.
+ *  Flushes the decoding buffer, releases resources, resets the decoder
+ *  settings to their defaults, and returns the decoder state to
+ *  FLAC__STREAM_DECODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated decode, it is not strictly
+ *  necessary to call this immediately before FLAC__stream_decoder_delete()
+ *  but it is good practice to match every FLAC__stream_decoder_init_*()
+ *  with a FLAC__stream_decoder_finish().
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if MD5 checking is on AND a STREAMINFO block was available
+ *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ *    signature does not match the one computed by the decoder; else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+
+/** Flush the stream input.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC.  This will also turn
+ *  off MD5 checking.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    error occurs (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
+
+/** Reset the decoding process.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA.  This is similar to
+ *  FLAC__stream_decoder_finish() except that the settings are
+ *  preserved; there is no need to call FLAC__stream_decoder_init_*()
+ *  before decoding again.  MD5 checking will be restored to its original
+ *  setting.
+ *
+ *  If the decoder is seekable, or was initialized with
+ *  FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(),
+ *  the decoder will also attempt to seek to the beginning of the file.
+ *  If this rewind fails, this function will return \c false.  It follows
+ *  that FLAC__stream_decoder_reset() cannot be used when decoding from
+ *  \c stdin.
+ *
+ *  If the decoder was initialized with FLAC__stream_encoder_init*_stream()
+ *  and is not seekable (i.e. no seek callback was provided or the seek
+ *  callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
+ *  is the duty of the client to start feeding data from the beginning of
+ *  the stream on the next FLAC__stream_decoder_process() or
+ *  FLAC__stream_decoder_process_interleaved() call.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation occurs
+ *    (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error
+ *    occurs (the state will be unchanged).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+
+/** Decode one metadata block or audio frame.
+ *  This version instructs the decoder to decode a either a single metadata
+ *  block or a single frame and stop, unless the callbacks return a fatal
+ *  error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  Depending on what was decoded, the metadata or write callback will be
+ *  called with the decoded metadata block or audio frame.
+ *
+ *  Unless there is a fatal read error or end of stream, this function
+ *  will return once one whole frame is decoded.  In other words, if the
+ *  stream is not synchronized or points to a corrupt frame header, the
+ *  decoder will continue to try and resync until it gets to a valid
+ *  frame, then decode one frame, then return.  If the decoder points to
+ *  a frame whose frame CRC in the frame footer does not match the
+ *  computed frame CRC, this function will issue a
+ *  FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ *  error callback, and return, having decoded one complete, although
+ *  corrupt, frame.  (Such corrupted frames are sent as silence of the
+ *  correct length to the write callback.)
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the metadata.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until all the metadata has been read, or until the
+ *  callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block is decoded, the metadata callback will be called
+ *  with the decoded metadata.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the stream.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until the end of stream (the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
+ *  callbacks return a fatal error.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block and frame is decoded, the metadata or write
+ *  callback will be called with the decoded metadata or frame.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
+
+/** Skip one audio frame.
+ *  This version instructs the decoder to 'skip' a single frame and stop,
+ *  unless the callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  The decoding flow is the same as what occurs when
+ *  FLAC__stream_decoder_process_single() is called to process an audio
+ *  frame, except that this function does not decode the parsed data into
+ *  PCM or call the write callback.  The integrity of the frame is still
+ *  checked the same way as in the other process functions.
+ *
+ *  This function will return once one whole frame is skipped, in the
+ *  same way that FLAC__stream_decoder_process_single() will return once
+ *  one whole frame is decoded.
+ *
+ *  This function can be used in more quickly determining FLAC frame
+ *  boundaries when decoding of the actual data is not needed, for
+ *  example when an application is separating a FLAC stream into frames
+ *  for editing or storing in a container.  To do this, the application
+ *  can use FLAC__stream_decoder_skip_single_frame() to quickly advance
+ *  to the next frame, then use
+ *  FLAC__stream_decoder_get_decode_position() to find the new frame
+ *  boundary.
+ *
+ *  This function should only be called when the stream has advanced
+ *  past all the metadata, otherwise it will return \c false.
+ *
+ * \param  decoder  An initialized decoder instance not in a metadata
+ *                  state.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), or if the decoder
+ *    is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ *    FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ *  Decoding will resume at the given sample.  Note that because of
+ *  this, the next write callback may contain a partial block.  The
+ *  client must support seeking the input or this function will fail
+ *  and return \c false.  Furthermore, if the decoder state is
+ *  \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
+ *  with FLAC__stream_decoder_flush() or reset with
+ *  FLAC__stream_decoder_reset() before decoding can continue.
+ *
+ * \param  decoder  A decoder instance.
+ * \param  sample   The target sample number to seek to.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h
new file mode 100644 (file)
index 0000000..dbbbb23
--- /dev/null
@@ -0,0 +1,1768 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_ENCODER_H
+#define FLAC__STREAM_ENCODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+#include "stream_decoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_stream_encoder stream encoder \endlink module.
+ */
+
+/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module describes the encoder layers provided by libFLAC.
+ *
+ * The stream encoder can be used to encode complete streams either to the
+ * client via callbacks, or directly to a file, depending on how it is
+ * initialized.  When encoding via callbacks, the client provides a write
+ * callback which will be called whenever FLAC data is ready to be written.
+ * If the client also supplies a seek callback, the encoder will also
+ * automatically handle the writing back of metadata discovered while
+ * encoding, like stream info, seek points offsets, etc.  When encoding to
+ * a file, the client needs only supply a filename or open \c FILE* and an
+ * optional progress callback for periodic notification of progress; the
+ * write and seek callbacks are supplied internally.  For more info see the
+ * \link flac_stream_encoder stream encoder \endlink module.
+ */
+
+/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface
+ *  \ingroup flac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  encoder.
+ *
+ * The stream encoder can encode to native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this encoder is as follows:
+ * - The program creates an instance of an encoder using
+ *   FLAC__stream_encoder_new().
+ * - The program overrides the default settings using
+ *   FLAC__stream_encoder_set_*() functions.  At a minimum, the following
+ *   functions should be called:
+ *   - FLAC__stream_encoder_set_channels()
+ *   - FLAC__stream_encoder_set_bits_per_sample()
+ *   - FLAC__stream_encoder_set_sample_rate()
+ *   - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC)
+ *   - FLAC__stream_encoder_set_total_samples_estimate() (if known)
+ * - If the application wants to control the compression level or set its own
+ *   metadata, then the following should also be called:
+ *   - FLAC__stream_encoder_set_compression_level()
+ *   - FLAC__stream_encoder_set_verify()
+ *   - FLAC__stream_encoder_set_metadata()
+ * - The rest of the set functions should only be called if the client needs
+ *   exact control over how the audio is compressed; thorough understanding
+ *   of the FLAC format is necessary to achieve good results.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for encoding using
+ *   - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE()
+ *     or FLAC__stream_encoder_init_file() for native FLAC
+ *   - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE()
+ *     or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC
+ * - The program calls FLAC__stream_encoder_process() or
+ *   FLAC__stream_encoder_process_interleaved() to encode data, which
+ *   subsequently calls the callbacks when there is encoder data ready
+ *   to be written.
+ * - The program finishes the encoding with FLAC__stream_encoder_finish(),
+ *   which causes the encoder to encode any data still in its input pipe,
+ *   update the metadata with the final encoding statistics if output
+ *   seeking is possible, and finally reset the encoder to the
+ *   uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__stream_encoder_delete().
+ *
+ * In more detail, the stream encoder functions similarly to the
+ * \link flac_stream_decoder stream decoder \endlink, but has fewer
+ * callbacks and more options.  Typically the client will create a new
+ * instance by calling FLAC__stream_encoder_new(), then set the necessary
+ * parameters with FLAC__stream_encoder_set_*(), and initialize it by
+ * calling one of the FLAC__stream_encoder_init_*() functions.
+ *
+ * Unlike the decoders, the stream encoder has many options that can
+ * affect the speed and compression ratio.  When setting these parameters
+ * you should have some basic knowledge of the format (see the
+ * <A HREF="../documentation.html#format">user-level documentation</A>
+ * or the <A HREF="../format.html">formal description</A>).  The
+ * FLAC__stream_encoder_set_*() functions themselves do not validate the
+ * values as many are interdependent.  The FLAC__stream_encoder_init_*()
+ * functions will do this, so make sure to pay attention to the state
+ * returned by FLAC__stream_encoder_init_*() to make sure that it is
+ * FLAC__STREAM_ENCODER_INIT_STATUS_OK.  Any parameters that are not set
+ * before FLAC__stream_encoder_init_*() will take on the defaults from
+ * the constructor.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the encoder to encode FLAC data to the client via
+ * callbacks, and two for encoding directly to a file.
+ *
+ * For encoding via callbacks, use FLAC__stream_encoder_init_stream().
+ * You must also supply a write callback which will be called anytime
+ * there is raw encoded data to write.  If the client can seek the output
+ * it is best to also supply seek and tell callbacks, as this allows the
+ * encoder to go back after encoding is finished to write back
+ * information that was collected while encoding, like seek point offsets,
+ * frame sizes, etc.
+ *
+ * For encoding directly to a file, use FLAC__stream_encoder_init_FILE()
+ * or FLAC__stream_encoder_init_file().  Then you must only supply a
+ * filename or open \c FILE*; the encoder will handle all the callbacks
+ * internally.  You may also supply a progress callback for periodic
+ * notification of the encoding progress.
+ *
+ * There are three similarly-named init functions for encoding to Ogg
+ * FLAC streams.  Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * The call to FLAC__stream_encoder_init_*() currently will also immediately
+ * call the write callback several times, once with the \c fLaC signature,
+ * and once for each encoded metadata block.  Note that for Ogg FLAC
+ * encoding you will usually get at least twice the number of callbacks than
+ * with native FLAC, one for the Ogg page header and one for the page body.
+ *
+ * After initializing the instance, the client may feed audio data to the
+ * encoder in one of two ways:
+ *
+ * - Channel separate, through FLAC__stream_encoder_process() - The client
+ *   will pass an array of pointers to buffers, one for each channel, to
+ *   the encoder, each of the same length.  The samples need not be
+ *   block-aligned, but each channel should have the same number of samples.
+ * - Channel interleaved, through
+ *   FLAC__stream_encoder_process_interleaved() - The client will pass a single
+ *   pointer to data that is channel-interleaved (i.e. channel0_sample0,
+ *   channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ *   Again, the samples need not be block-aligned but they must be
+ *   sample-aligned, i.e. the first value should be channel0_sample0 and
+ *   the last value channelN_sampleM.
+ *
+ * Note that for either process call, each sample in the buffers should be a
+ * signed integer, right-justified to the resolution set by
+ * FLAC__stream_encoder_set_bits_per_sample().  For example, if the resolution
+ * is 16 bits per sample, the samples should all be in the range [-32768,32767].
+ *
+ * When the client is finished encoding data, it calls
+ * FLAC__stream_encoder_finish(), which causes the encoder to encode any
+ * data still in its input pipe, and call the metadata callback with the
+ * final encoding statistics.  Then the instance may be deleted with
+ * FLAC__stream_encoder_delete() or initialized again to encode another
+ * stream.
+ *
+ * For programs that write their own metadata, but that do not know the
+ * actual metadata until after encoding, it is advantageous to instruct
+ * the encoder to write a PADDING block of the correct size, so that
+ * instead of rewriting the whole stream after encoding, the program can
+ * just overwrite the PADDING block.  If only the maximum size of the
+ * metadata is known, the program can write a slightly larger padding
+ * block, then split it after encoding.
+ *
+ * Make sure you understand how lengths are calculated.  All FLAC metadata
+ * blocks have a 4 byte header which contains the type and length.  This
+ * length does not include the 4 bytes of the header.  See the format page
+ * for the specification of metadata blocks and their lengths.
+ *
+ * \note
+ * If you are writing the FLAC data to a file via callbacks, make sure it
+ * is open for update (e.g. mode "w+" for stdio streams).  This is because
+ * after the first encoding pass, the encoder will try to seek back to the
+ * beginning of the stream, to the STREAMINFO block, to write some data
+ * there.  (If using FLAC__stream_encoder_init*_file() or
+ * FLAC__stream_encoder_init*_FILE(), the file is managed internally.)
+ *
+ * \note
+ * The "set" functions may only be called when the encoder is in the
+ * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but
+ * before FLAC__stream_encoder_init_*().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_encoder_finish() resets all settings to the constructor
+ * defaults.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamEncoder.
+ *
+ * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state().
+ *
+ * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK
+ * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and
+ * must be deleted with FLAC__stream_encoder_delete().
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_OK = 0,
+       /**< The encoder is in the normal OK state and samples can be processed. */
+
+       FLAC__STREAM_ENCODER_UNINITIALIZED,
+       /**< The encoder is in the uninitialized state; one of the
+        * FLAC__stream_encoder_init_*() functions must be called before samples
+        * can be processed.
+        */
+
+       FLAC__STREAM_ENCODER_OGG_ERROR,
+       /**< An error occurred in the underlying Ogg layer.  */
+
+       FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR,
+       /**< An error occurred in the underlying verify stream decoder;
+        * check FLAC__stream_encoder_get_verify_decoder_state().
+        */
+
+       FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA,
+       /**< The verify decoder detected a mismatch between the original
+        * audio signal and the decoded audio signal.
+        */
+
+       FLAC__STREAM_ENCODER_CLIENT_ERROR,
+       /**< One of the callbacks returned a fatal error. */
+
+       FLAC__STREAM_ENCODER_IO_ERROR,
+       /**< An I/O error occurred while opening/reading/writing a file.
+        * Check \c errno.
+        */
+
+       FLAC__STREAM_ENCODER_FRAMING_ERROR,
+       /**< An error occurred while writing the stream; usually, the
+        * write_callback returned an error.
+        */
+
+       FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR
+       /**< Memory allocation failed. */
+
+} FLAC__StreamEncoderState;
+
+/** Maps a FLAC__StreamEncoderState to a C string.
+ *
+ *  Using a FLAC__StreamEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_encoder_init_*() functions.
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0,
+       /**< Initialization was successful. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR,
+       /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+       /**< The library was not compiled with support for the given container
+        * format.
+        */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS,
+       /**< A required callback was not supplied. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS,
+       /**< The encoder has an invalid setting for number of channels. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE,
+       /**< The encoder has an invalid setting for bits-per-sample.
+        * FLAC supports 4-32 bps but the reference encoder currently supports
+        * only up to 24 bps.
+        */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE,
+       /**< The encoder has an invalid setting for the input sample rate. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE,
+       /**< The encoder has an invalid setting for the block size. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER,
+       /**< The encoder has an invalid setting for the maximum LPC order. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION,
+       /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER,
+       /**< The specified block size is less than the maximum LPC order. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE,
+       /**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> but other settings violate it. */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA,
+       /**< The metadata input to the encoder is invalid, in one of the following ways:
+        * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0
+        * - One of the metadata blocks contains an undefined type
+        * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal()
+        * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal()
+        * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block
+        */
+
+       FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED
+       /**< FLAC__stream_encoder_init_*() was called when the encoder was
+        * already initialized, usually because
+        * FLAC__stream_encoder_finish() was not called.
+        */
+
+} FLAC__StreamEncoderInitStatus;
+
+/** Maps a FLAC__StreamEncoderInitStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderInitStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder read callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE,
+       /**< The read was OK and decoding can continue. */
+
+       FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM,
+       /**< The read was attempted at the end of the stream. */
+
+       FLAC__STREAM_ENCODER_READ_STATUS_ABORT,
+       /**< An unrecoverable error occurred. */
+
+       FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED
+       /**< Client does not support reading back from the output. */
+
+} FLAC__StreamEncoderReadStatus;
+
+/** Maps a FLAC__StreamEncoderReadStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderReadStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder write callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0,
+       /**< The write was OK and encoding can continue. */
+
+       FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR
+       /**< An unrecoverable error occurred.  The encoder will return from the process call. */
+
+} FLAC__StreamEncoderWriteStatus;
+
+/** Maps a FLAC__StreamEncoderWriteStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderWriteStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder seek callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_SEEK_STATUS_OK,
+       /**< The seek was OK and encoding can continue. */
+
+       FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR,
+       /**< An unrecoverable error occurred. */
+
+       FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+       /**< Client does not support seeking. */
+
+} FLAC__StreamEncoderSeekStatus;
+
+/** Maps a FLAC__StreamEncoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder tell callback.
+ */
+typedef enum {
+
+       FLAC__STREAM_ENCODER_TELL_STATUS_OK,
+       /**< The tell was OK and encoding can continue. */
+
+       FLAC__STREAM_ENCODER_TELL_STATUS_ERROR,
+       /**< An unrecoverable error occurred. */
+
+       FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+       /**< Client does not support seeking. */
+
+} FLAC__StreamEncoderTellStatus;
+
+/** Maps a FLAC__StreamEncoderTellStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamEncoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamEncoderProtected;
+struct FLAC__StreamEncoderPrivate;
+/** The opaque structure definition for the stream encoder type.
+ *  See the \link flac_stream_encoder stream encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+       struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+       struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamEncoder;
+
+/** Signature for the read callback.
+ *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_encoder_init_ogg_stream() if seeking is supported.
+ *  The supplied function will be called when the encoder needs to read back
+ *  encoded data.  This happens during the metadata callback, when the encoder
+ *  has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered
+ *  while encoding.  The address of the buffer to be filled is supplied, along
+ *  with the number of bytes the buffer can hold.  The callback may choose to
+ *  supply less data and modify the byte count but must be careful not to
+ *  overflow the buffer.  The callback then returns a status code chosen from
+ *  FLAC__StreamEncoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(*bytes > 0) {
+ *     *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ *     if(ferror(file))
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ *     else if(*bytes == 0)
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+ *     else
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+ *   }
+ *   else
+ *     return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be encoded.
+ * \param  bytes    A pointer to the size of the buffer.  On entry
+ *                  to the callback, it contains the maximum number
+ *                  of bytes that may be stored in \a buffer.  The
+ *                  callee must set it to the actual number of bytes
+ *                  stored (0 in case of error or end-of-stream) before
+ *                  returning.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderReadStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the write callback.
+ *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  by the encoder anytime there is raw encoded data ready to write.  It may
+ *  include metadata mixed with encoded audio frames and the data is not
+ *  guaranteed to be aligned on frame or metadata block boundaries.
+ *
+ *  The only duty of the callback is to write out the \a bytes worth of data
+ *  in \a buffer to the current position in the output stream.  The arguments
+ *  \a samples and \a current_frame are purely informational.  If \a samples
+ *  is greater than \c 0, then \a current_frame will hold the current frame
+ *  number that is being written; otherwise it indicates that the write
+ *  callback is being called to write metadata.
+ *
+ * \note
+ * Unlike when writing to native FLAC, when writing to Ogg FLAC the
+ * write callback will be called twice when writing each audio
+ * frame; once for the page header, and once for the page body.
+ * When writing the page header, the \a samples argument to the
+ * write callback will be \c 0.
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   An array of encoded data of length \a bytes.
+ * \param  bytes    The byte length of \a buffer.
+ * \param  samples  The number of samples encoded by \a buffer.
+ *                  \c 0 has a special meaning; see above.
+ * \param  current_frame  The number of the current frame being encoded.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  when the encoder needs to seek the output stream.  The encoder will pass
+ *  the absolute byte offset to seek to, 0 meaning the beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+ *   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+ *   else
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  when the encoder needs to know the current position of the output stream.
+ *
+ * \warning
+ * The callback must return the true current byte offset of the output to
+ * which the encoder is writing.  If you are buffering the output, make
+ * sure and take this into account.  If you are writing directly to a
+ * FILE* from your write callback, ftell() is sufficient.  If you are
+ * writing directly to a file descriptor from your write callback, you
+ * can use lseek(fd, SEEK_CUR, 0).  The encoder may later seek back to
+ * these points to rewrite metadata after encoding.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   off_t pos;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+ *   else if((pos = ftello(file)) < 0)
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+ *   else {
+ *     *absolute_byte_offset = (FLAC__uint64)pos;
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The address at which to store the current
+ *                               position of the output.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  once at the end of encoding with the populated STREAMINFO structure.  This
+ *  is so the client can seek back to the beginning of the file and write the
+ *  STREAMINFO block with the correct statistics after encoding (like
+ *  minimum/maximum frame size and total samples).
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder      The encoder instance calling the callback.
+ * \param  metadata     The final populated STREAMINFO block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_init_*().
+ */
+typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the progress callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE().
+ *  The supplied function will be called when the encoder has finished
+ *  writing a frame.  The \c total_frames_estimate argument to the
+ *  callback will be based on the value from
+ *  FLAC__stream_encoder_set_total_samples_estimate().
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder          The encoder instance calling the callback.
+ * \param  bytes_written    Bytes written so far.
+ * \param  samples_written  Samples written so far.
+ * \param  frames_written   Frames written so far.
+ * \param  total_frames_estimate  The estimate of the total number of
+ *                                frames to be written.
+ * \param  client_data      The callee's client data set through
+ *                          FLAC__stream_encoder_init_*().
+ */
+typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream encoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__stream_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__StreamEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void);
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream to use in the Ogg container.
+ *
+ * \note
+ * This does not need to be set for native FLAC encoding.
+ *
+ * \note
+ * It is recommended to set a serial number explicitly as the default of '0'
+ * may collide with other streams.
+ *
+ * \default \c 0
+ * \param  encoder        An encoder instance to set.
+ * \param  serial_number  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number);
+
+/** Set the "verify" flag.  If \c true, the encoder will verify it's own
+ *  encoded output by feeding it through an internal decoder and comparing
+ *  the original signal against the decoded signal.  If a mismatch occurs,
+ *  the process call will return \c false.  Note that this will slow the
+ *  encoding process by the extra time required for decoding and comparison.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the <A HREF="../format.html#subset">Subset</A> flag.  If \c true,
+ *  the encoder will comply with the Subset and will check the
+ *  settings during FLAC__stream_encoder_init_*() to see if all settings
+ *  comply.  If \c false, the settings may take advantage of the full
+ *  range that the format allows.
+ *
+ *  Make sure you know what it entails before setting this to \c false.
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the number of channels to be encoded.
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample resolution of the input to be encoded.
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample rate (in Hz) of the input to be encoded.
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the compression level
+ *
+ * The compression level is roughly proportional to the amount of effort
+ * the encoder expends to compress the file.  A higher level usually
+ * means more computation but higher compression.  The default level is
+ * suitable for most applications.
+ *
+ * Currently the levels range from \c 0 (fastest, least compression) to
+ * \c 8 (slowest, most compression).  A value larger than \c 8 will be
+ * treated as \c 8.
+ *
+ * This function automatically calls the following other \c _set_
+ * functions with appropriate values, so the client does not need to
+ * unless it specifically wants to override them:
+ * - FLAC__stream_encoder_set_do_mid_side_stereo()
+ * - FLAC__stream_encoder_set_loose_mid_side_stereo()
+ * - FLAC__stream_encoder_set_apodization()
+ * - FLAC__stream_encoder_set_max_lpc_order()
+ * - FLAC__stream_encoder_set_qlp_coeff_precision()
+ * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search()
+ * - FLAC__stream_encoder_set_do_escape_coding()
+ * - FLAC__stream_encoder_set_do_exhaustive_model_search()
+ * - FLAC__stream_encoder_set_min_residual_partition_order()
+ * - FLAC__stream_encoder_set_max_residual_partition_order()
+ * - FLAC__stream_encoder_set_rice_parameter_search_dist()
+ *
+ * The actual values set for each level are:
+ * <table>
+ * <tr>
+ *  <td><b>level</b><td>
+ *  <td>do mid-side stereo<td>
+ *  <td>loose mid-side stereo<td>
+ *  <td>apodization<td>
+ *  <td>max lpc order<td>
+ *  <td>qlp coeff precision<td>
+ *  <td>qlp coeff prec search<td>
+ *  <td>escape coding<td>
+ *  <td>exhaustive model search<td>
+ *  <td>min residual partition order<td>
+ *  <td>max residual partition order<td>
+ *  <td>rice parameter search dist<td>
+ * </tr>
+ * <tr>  <td><b>0</b><td>  <td>false<td>  <td>false<td>  <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>1</b><td>  <td>true<td>   <td>true<td>   <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>2</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>3</b><td>  <td>false<td>  <td>false<td>  <td>tukey(0.5)<td>  <td>6<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>4<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>4</b><td>  <td>true<td>   <td>true<td>   <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>4<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>5</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>5<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>6</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>6<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>7</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>true<td>   <td>0<td>  <td>6<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>8</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>12<td>  <td>0<td>  <td>false<td>  <td>false<td>  <td>true<td>   <td>0<td>  <td>6<td>  <td>0<td>  </tr>
+ * </table>
+ *
+ * \default \c 5
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the blocksize to use while encoding.
+ *
+ * The number of samples to use per frame.  Use \c 0 to let the encoder
+ * estimate a blocksize; this is usually best.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set to \c true to enable mid-side encoding on stereo input.  The
+ *  number of channels must be 2 for this to have any effect.  Set to
+ *  \c false to use only independent channel coding.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c true to enable adaptive switching between mid-side and
+ *  left-right encoding on stereo input.  Set to \c false to use
+ *  exhaustive searching.  Setting this to \c true requires
+ *  FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to
+ *  \c true in order to have any effect.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Sets the apodization function(s) the encoder will use when windowing
+ *  audio data for LPC analysis.
+ *
+ * The \a specification is a plain ASCII string which specifies exactly
+ * which functions to use.  There may be more than one (up to 32),
+ * separated by \c ';' characters.  Some functions take one or more
+ * comma-separated arguments in parentheses.
+ *
+ * The available functions are \c bartlett, \c bartlett_hann,
+ * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
+ * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
+ * \c rectangle, \c triangle, \c tukey(P), \c welch.
+ *
+ * For \c gauss(STDDEV), STDDEV specifies the standard deviation
+ * (0<STDDEV<=0.5).
+ *
+ * For \c tukey(P), P specifies the fraction of the window that is
+ * tapered (0<=P<=1).  P=0 corresponds to \c rectangle and P=1
+ * corresponds to \c hann.
+ *
+ * Example specifications are \c "blackman" or
+ * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
+ *
+ * Any function that is specified erroneously is silently dropped.  Up
+ * to 32 functions are kept, the rest are dropped.  If the specification
+ * is empty the encoder defaults to \c "tukey(0.5)".
+ *
+ * When more than one function is specified, then for every subframe the
+ * encoder will try each of them separately and choose the window that
+ * results in the smallest compressed subframe.
+ *
+ * Note that each function specified causes the encoder to occupy a
+ * floating point array in which to store the window.
+ *
+ * \default \c "tukey(0.5)"
+ * \param  encoder        An encoder instance to set.
+ * \param  specification  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code specification != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification);
+
+/** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the precision, in bits, of the quantized linear predictor
+ *  coefficients, or \c 0 to let the encoder select it based on the
+ *  blocksize.
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set to \c false to use only the specified quantized linear predictor
+ *  coefficient precision, or \c true to search neighboring precision
+ *  values and use the best one.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Deprecated.  Setting this value has no effect.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c false to let the encoder estimate the best model order
+ *  based on the residual signal energy, or \c true to force the
+ *  encoder to evaluate all order models and select the best.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the minimum partition order to search when coding the residual.
+ *  This is used in tandem with
+ *  FLAC__stream_encoder_set_max_residual_partition_order().
+ *
+ *  The partition order determines the context size in the residual.
+ *  The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ *  Set both min and max values to \c 0 to force a single context,
+ *  whose Rice parameter is based on the residual signal variance.
+ *  Otherwise, set a min and max order, and the encoder will search
+ *  all orders, using the mean of each context for its Rice parameter,
+ *  and use the best.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the maximum partition order to search when coding the residual.
+ *  This is used in tandem with
+ *  FLAC__stream_encoder_set_min_residual_partition_order().
+ *
+ *  The partition order determines the context size in the residual.
+ *  The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ *  Set both min and max values to \c 0 to force a single context,
+ *  whose Rice parameter is based on the residual signal variance.
+ *  Otherwise, set a min and max order, and the encoder will search
+ *  all orders, using the mean of each context for its Rice parameter,
+ *  and use the best.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Deprecated.  Setting this value has no effect.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set an estimate of the total samples that will be encoded.
+ *  This is merely an estimate and may be set to \c 0 if unknown.
+ *  This value will be written to the STREAMINFO block before encoding,
+ *  and can remove the need for the caller to rewrite the value later
+ *  if the value is known before encoding.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value);
+
+/** Set the metadata blocks to be emitted to the stream before encoding.
+ *  A value of \c NULL, \c 0 implies no metadata; otherwise, supply an
+ *  array of pointers to metadata blocks.  The array is non-const since
+ *  the encoder may need to change the \a is_last flag inside them, and
+ *  in some cases update seek point offsets.  Otherwise, the encoder will
+ *  not modify or free the blocks.  It is up to the caller to free the
+ *  metadata blocks after encoding finishes.
+ *
+ * \note
+ * The encoder stores only copies of the pointers in the \a metadata array;
+ * the metadata blocks themselves must survive at least until after
+ * FLAC__stream_encoder_finish() returns.  Do not free the blocks until then.
+ *
+ * \note
+ * The STREAMINFO block is always written and no STREAMINFO block may
+ * occur in the supplied array.
+ *
+ * \note
+ * By default the encoder does not create a SEEKTABLE.  If one is supplied
+ * in the \a metadata array, but the client has specified that it does not
+ * support seeking, then the SEEKTABLE will be written verbatim.  However
+ * by itself this is not very useful as the client will not know the stream
+ * offsets for the seekpoints ahead of time.  In order to get a proper
+ * seektable the client must support seeking.  See next note.
+ *
+ * \note
+ * SEEKTABLE blocks are handled specially.  Since you will not know
+ * the values for the seek point stream offsets, you should pass in
+ * a SEEKTABLE 'template', that is, a SEEKTABLE object with the
+ * required sample numbers (or placeholder points), with \c 0 for the
+ * \a frame_samples and \a stream_offset fields for each point.  If the
+ * client has specified that it supports seeking by providing a seek
+ * callback to FLAC__stream_encoder_init_stream() or both seek AND read
+ * callback to FLAC__stream_encoder_init_ogg_stream() (or by using
+ * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()),
+ * then while it is encoding the encoder will fill the stream offsets in
+ * for you and when encoding is finished, it will seek back and write the
+ * real values into the SEEKTABLE block in the stream.  There are helper
+ * routines for manipulating seektable template blocks; see metadata.h:
+ * FLAC__metadata_object_seektable_template_*().  If the client does
+ * not support seeking, the SEEKTABLE will have inaccurate offsets which
+ * will slow down or remove the ability to seek in the FLAC stream.
+ *
+ * \note
+ * The encoder instance \b will modify the first \c SEEKTABLE block
+ * as it transforms the template to a valid seektable while encoding,
+ * but it is still up to the caller to free all metadata blocks after
+ * encoding.
+ *
+ * \note
+ * A VORBIS_COMMENT block may be supplied.  The vendor string in it
+ * will be ignored.  libFLAC will use it's own vendor string. libFLAC
+ * will not modify the passed-in VORBIS_COMMENT's vendor string, it
+ * will simply write it's own into the stream.  If no VORBIS_COMMENT
+ * block is present in the \a metadata array, libFLAC will write an
+ * empty one, containing only the vendor string.
+ *
+ * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be
+ * the second metadata block of the stream.  The encoder already supplies
+ * the STREAMINFO block automatically.  If \a metadata does not contain a
+ * VORBIS_COMMENT block, the encoder will supply that too.  Otherwise, if
+ * \a metadata does contain a VORBIS_COMMENT block and it is not the
+ * first, the init function will reorder \a metadata by moving the
+ * VORBIS_COMMENT block to the front; the relative ordering of the other
+ * blocks will remain as they were.
+ *
+ * \note The Ogg FLAC mapping limits the number of metadata blocks per
+ * stream to \c 65535.  If \a num_blocks exceeds this the function will
+ * return \c false.
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ *    \c false if the encoder is already initialized, or if
+ *    \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The current encoder state.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the state of the verify stream decoder.
+ *  Useful when the stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The verify stream decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the
+ *  verify decoder's state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Useful when the stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.  The arguments should
+ *  be addresses in which the stats will be returned, or NULL if value
+ *  is not desired.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_verify().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
+
+/** Get the <A HREF="../format.html#subset>Subset</A> flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_streamable_subset().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_channels().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_bits_per_sample().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_sample_rate().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
+
+/** Get the blocksize setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_blocksize().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_get_do_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_loose_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_max_lpc_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_qlp_coeff_precision().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_qlp_coeff_prec_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_escape_coding().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_exhaustive_model_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_min_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_max_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_rice_parameter_search_dist().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ *  The encoder merely mimics back the value given to
+ *  FLAC__stream_encoder_set_total_samples_estimate() since it has no
+ *  other way of knowing how many samples the client will encode.
+ *
+ * \param  encoder  An encoder instance to set.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See FLAC__stream_encoder_get_total_samples_estimate().
+ */
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder);
+
+/** Initialize the encoder instance to encode native FLAC streams.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  native FLAC stream. I/O is performed via callbacks to the client.
+ *  For encoding to a plain file via filename or open \c FILE*,
+ *  FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ *  The call to FLAC__stream_encoder_init_stream() currently will also
+ *  immediately call the write callback several times, once with the \c fLaC
+ *  signature, and once for each encoded metadata block.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  write_callback     See FLAC__StreamEncoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamEncoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  The encoder uses seeking to go back
+ *                            and write some some stream statistics to the
+ *                            STREAMINFO block; this is recommended but not
+ *                            necessary to create a valid FLAC stream.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  tell_callback      See FLAC__StreamEncoderTellCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is \c NULL then
+ *                            this argument will be ignored.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  metadata_callback  See FLAC__StreamEncoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.  If the client provides a seek callback,
+ *                            this function is not necessary as the encoder
+ *                            will automatically seek back and update the
+ *                            STREAMINFO block.  It may also be \c NULL if the
+ *                            client does not support seeking, since it will
+ *                            have no way of going back to update the
+ *                            STREAMINFO.  However the client can still supply
+ *                            a callback if it would like to know the details
+ *                            from the STREAMINFO.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC streams.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a FLAC
+ *  stream in an Ogg container.  I/O is performed via callbacks to the
+ *  client.  For encoding to a plain file via filename or open \c FILE*,
+ *  FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ *  The call to FLAC__stream_encoder_init_ogg_stream() currently will also
+ *  immediately call the write callback several times to write the metadata
+ *  packets.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  read_callback      See FLAC__StreamEncoderReadCallback.  This
+ *                            pointer must not be \c NULL if \a seek_callback
+ *                            is non-NULL since they are both needed to be
+ *                            able to write data back to the Ogg FLAC stream
+ *                            in the post-encode phase.
+ * \param  write_callback     See FLAC__StreamEncoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamEncoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  The encoder uses seeking to go back
+ *                            and write some some stream statistics to the
+ *                            STREAMINFO block; this is recommended but not
+ *                            necessary to create a valid FLAC stream.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  tell_callback      See FLAC__StreamEncoderTellCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is \c NULL then
+ *                            this argument will be ignored.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  metadata_callback  See FLAC__StreamEncoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.  If the client provides a seek callback,
+ *                            this function is not necessary as the encoder
+ *                            will automatically seek back and update the
+ *                            STREAMINFO block.  It may also be \c NULL if the
+ *                            client does not support seeking, since it will
+ *                            have no way of going back to update the
+ *                            STREAMINFO.  However the client can still supply
+ *                            a callback if it would like to know the details
+ *                            from the STREAMINFO.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  plain native FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_encoder_init_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  file               An open file.  The file should have been opened
+ *                            with mode \c "w+b" and rewound.  The file
+ *                            becomes owned by the encoder and should not be
+ *                            manipulated by the client while encoding.
+ *                            Unless \a file is \c stdout, it will be closed
+ *                            when FLAC__stream_encoder_finish() is called.
+ *                            Note however that a proper SEEKTABLE cannot be
+ *                            created when encoding to \c stdout since it is
+ *                            not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  plain Ogg FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  file               An open file.  The file should have been opened
+ *                            with mode \c "w+b" and rewound.  The file
+ *                            becomes owned by the encoder and should not be
+ *                            manipulated by the client while encoding.
+ *                            Unless \a file is \c stdout, it will be closed
+ *                            when FLAC__stream_encoder_finish() is called.
+ *                            Note however that a proper SEEKTABLE cannot be
+ *                            created when encoding to \c stdout since it is
+ *                            not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a plain
+ *  FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
+ *  with Unicode filenames on Windows), you must use
+ *  FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  filename           The name of the file to encode to.  The file will
+ *                            be opened with fopen().  Use \c NULL to encode to
+ *                            \c stdout.  Note however that a proper SEEKTABLE
+ *                            cannot be created when encoding to \c stdout since
+ *                            it is not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a plain
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
+ *  with Unicode filenames on Windows), you must use
+ *  FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  filename           The name of the file to encode to.  The file will
+ *                            be opened with fopen().  Use \c NULL to encode to
+ *                            \c stdout.  Note however that a proper SEEKTABLE
+ *                            cannot be created when encoding to \c stdout since
+ *                            it is not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  FLAC__STREAM_ENCODER_UNINITIALIZED.  Note that this can generate
+ *  one or more write callbacks before returning, and will generate
+ *  a metadata callback.
+ *
+ *  Note that in the course of processing the last frame, errors can
+ *  occur, so the caller should be sure to check the return value to
+ *  ensure the file was encoded properly.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before FLAC__stream_encoder_delete()
+ *  but it is good practice to match every FLAC__stream_encoder_init_*()
+ *  with a FLAC__stream_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if an error occurred processing the last frame; or if verify
+ *    mode is set (see FLAC__stream_encoder_set_verify()), there was a
+ *    verify mismatch; else \c true.  If \c false, caller should check the
+ *    state with FLAC__stream_encoder_get_state() for more information
+ *    about the error.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
+
+/** Submit data for encoding.
+ *  This version allows you to supply the input data via an array of
+ *  pointers, each pointer pointing to an array of \a samples samples
+ *  representing one channel.  The samples need not be block-aligned,
+ *  but each channel should have the same number of samples.  Each sample
+ *  should be a signed integer, right-justified to the resolution set by
+ *  FLAC__stream_encoder_set_bits_per_sample().  For example, if the
+ *  resolution is 16 bits per sample, the samples should all be in the
+ *  range [-32768,32767].
+ *
+ *  For applications where channel order is important, channels must
+ *  follow the order as described in the
+ *  <A HREF="../format.html#frame_header">frame header</A>.
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ *  This version allows you to supply the input data where the channels
+ *  are interleaved into a single array (i.e. channel0_sample0,
+ *  channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ *  The samples need not be block-aligned but they must be
+ *  sample-aligned, i.e. the first value should be channel0_sample0
+ *  and the last value channelN_sampleM.  Each sample should be a signed
+ *  integer, right-justified to the resolution set by
+ *  FLAC__stream_encoder_set_bits_per_sample().  For example, if the
+ *  resolution is 16 bits per sample, the samples should all be in the
+ *  range [-32768,32767].
+ *
+ *  For applications where channel order is important, channels must
+ *  follow the order as described in the
+ *  <A HREF="../format.html#frame_header">frame header</A>.
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  FLAC__stream_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..b45dc84
--- /dev/null
@@ -0,0 +1,22 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = FLAC++
+endif
+
+SUBDIRS = FLAC $(CPPLIBS_DIRS) share test_libs_common
diff --git a/include/share/Makefile.am b/include/share/Makefile.am
new file mode 100644 (file)
index 0000000..513828b
--- /dev/null
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = grabbag
+
+EXTRA_DIST = \
+       alloc.h \
+       getopt.h \
+       grabbag.h \
+       replaygain_analysis.h \
+       replaygain_synthesis.h \
+       utf8.h
diff --git a/include/share/alloc.h b/include/share/alloc.h
new file mode 100644 (file)
index 0000000..812aa69
--- /dev/null
@@ -0,0 +1,212 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__SHARE__ALLOC_H
+#define FLAC__SHARE__ALLOC_H
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
+ * before #including this file,  otherwise SIZE_MAX might not be defined
+ */
+
+#include <limits.h> /* for SIZE_MAX */
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
+#endif
+#include <stdlib.h> /* for size_t, malloc(), etc */
+
+#ifndef SIZE_MAX
+# ifndef SIZE_T_MAX
+#  ifdef _MSC_VER
+#   define SIZE_T_MAX UINT_MAX
+#  else
+#   error
+#  endif
+# endif
+# define SIZE_MAX SIZE_T_MAX
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/* avoid malloc()ing 0 bytes, see:
+ * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
+*/
+static FLaC__INLINE void *safe_malloc_(size_t size)
+{
+       /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       if(!size)
+               size++;
+       return malloc(size);
+}
+
+static FLaC__INLINE void *safe_calloc_(size_t nmemb, size_t size)
+{
+       if(!nmemb || !size)
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       return calloc(nmemb, size);
+}
+
+/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
+
+static FLaC__INLINE void *safe_malloc_add_2op_(size_t size1, size_t size2)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       return safe_malloc_(size2);
+}
+
+static FLaC__INLINE void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       return safe_malloc_(size3);
+}
+
+static FLaC__INLINE void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       size4 += size3;
+       if(size4 < size3)
+               return 0;
+       return safe_malloc_(size4);
+}
+
+static FLaC__INLINE void *safe_malloc_mul_2op_(size_t size1, size_t size2)
+#if 0
+needs support for cases where sizeof(size_t) != 4
+{
+       /* could be faster #ifdef'ing off SIZEOF_SIZE_T */
+       if(sizeof(size_t) == 4) {
+               if ((double)size1 * (double)size2 < 4294967296.0)
+                       return malloc(size1*size2);
+       }
+       return 0;
+}
+#else
+/* better? */
+{
+       if(!size1 || !size2)
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return malloc(size1*size2);
+}
+#endif
+
+static FLaC__INLINE void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || !size2 || !size3)
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       size1 *= size2;
+       if(size1 > SIZE_MAX / size3)
+               return 0;
+       return malloc(size1*size3);
+}
+
+/* size1*size2 + size3 */
+static FLaC__INLINE void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || !size2)
+               return safe_malloc_(size3);
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return safe_malloc_add_2op_(size1*size2, size3);
+}
+
+/* size1 * (size2 + size3) */
+static FLaC__INLINE void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || (!size2 && !size3))
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       size2 += size3;
+       if(size2 < size3)
+               return 0;
+       return safe_malloc_mul_2op_(size1, size2);
+}
+
+static FLaC__INLINE void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       return realloc(ptr, size2);
+}
+
+static FLaC__INLINE void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       return realloc(ptr, size3);
+}
+
+static FLaC__INLINE void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       size4 += size3;
+       if(size4 < size3)
+               return 0;
+       return realloc(ptr, size4);
+}
+
+static FLaC__INLINE void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
+{
+       if(!size1 || !size2)
+               return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return realloc(ptr, size1*size2);
+}
+
+/* size1 * (size2 + size3) */
+static FLaC__INLINE void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || (!size2 && !size3))
+               return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+       size2 += size3;
+       if(size2 < size3)
+               return 0;
+       return safe_realloc_mul_2op_(ptr, size1, size2);
+}
+
+#endif
diff --git a/include/share/getopt.h b/include/share/getopt.h
new file mode 100644 (file)
index 0000000..1b314b2
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+       NOTE:
+       I cannot get the vanilla getopt code to work (i.e. compile only what
+       is needed and not duplicate symbols found in the standard library)
+       on all the platforms that FLAC supports.  In particular the gating
+       of code with the ELIDE_CODE #define is not accurate enough on systems
+       that are POSIX but not glibc.  If someone has a patch that works on
+       GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+               http://sourceforge.net/projects/flac
+
+       In the meantime I have munged the global symbols and removed gates
+       around code, while at the same time trying to touch the original as
+       little as possible.
+*/
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef SHARE__GETOPT_H
+#define SHARE__GETOPT_H
+
+/*[JEC] was:#ifndef __need_getopt*/
+/*[JEC] was:# define _GETOPT_H 1*/
+/*[JEC] was:#endif*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `share__getopt' to the caller.
+   When `share__getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *share__optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `share__getopt'.
+
+   On entry to `share__getopt', zero means this is the first call; initialize.
+
+   When `share__getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `share__optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int share__optind;
+
+/* Callers store zero here to inhibit the error message `share__getopt' prints
+   for unrecognized options.  */
+
+extern int share__opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int share__optopt;
+
+/*[JEC] was:#ifndef __need_getopt */
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to share__getopt_long or share__getopt_long_only is a vector
+   of `struct share__option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   share__no_argument          (or 0) if the option does not take an argument,
+   share__required_argument    (or 1) if the option requires an argument,
+   share__optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `share__optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `share__getopt'
+   returns the contents of the `val' field.  */
+
+struct share__option
+{
+# if defined __STDC__ && __STDC__
+  const char *name;
+# else
+  char *name;
+# endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct share__option'.  */
+
+# define share__no_argument            0
+# define share__required_argument      1
+# define share__optional_argument      2
+/*[JEC] was:#endif*/   /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+   arguments in ARGV (ARGC of them, minus the program name) for
+   options given in OPTS.
+
+   Return the option character from OPTS just read.  Return -1 when
+   there are no more options.  For unrecognized options, or options
+   missing arguments, `share__optopt' is set to the option letter, and '?' is
+   returned.
+
+   The OPTS string is a list of characters which are recognized option
+   letters, optionally followed by colons, specifying that that letter
+   takes an argument, to be placed in `share__optarg'.
+
+   If a letter in OPTS is followed by two colons, its argument is
+   optional.  This behavior is specific to the GNU `share__getopt'.
+
+   The argument `--' causes premature termination of argument
+   scanning, explicitly telling `share__getopt' that there are no more
+   options.
+
+   If OPTS begins with `--', then non-option arguments are treated as
+   arguments to the option '\0'.  This behavior is specific to the GNU
+   `share__getopt'.  */
+
+/*[JEC] was:#if defined __STDC__ && __STDC__*/
+/*[JEC] was:# ifdef __GNU_LIBRARY__*/
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int share__getopt (int argc, char *const *argv, const char *shortopts);
+/*[JEC] was:# else*/ /* not __GNU_LIBRARY__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# endif*/ /* __GNU_LIBRARY__ */
+
+/*[JEC] was:# ifndef __need_getopt*/
+extern int share__getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct share__option *longopts, int *longind);
+extern int share__getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct share__option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int share___getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct share__option *longopts, int *longind,
+                            int long_only);
+/*[JEC] was:# endif*/
+/*[JEC] was:#else*/ /* not __STDC__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# ifndef __need_getopt*/
+/*[JEC] was:extern int getopt_long ();*/
+/*[JEC] was:extern int getopt_long_only ();*/
+
+/*[JEC] was:extern int _getopt_internal ();*/
+/*[JEC] was:# endif*/
+/*[JEC] was:#endif*/ /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations.  */
+/*[JEC] was:#undef __need_getopt*/
+
+#endif /* getopt.h */
diff --git a/include/share/grabbag.h b/include/share/grabbag.h
new file mode 100644 (file)
index 0000000..42c6998
--- /dev/null
@@ -0,0 +1,29 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef SHARE__GRABBAG_H
+#define SHARE__GRABBAG_H
+
+/* These can't be included by themselves, only from within grabbag.h */
+#include "grabbag/cuesheet.h"
+#include "grabbag/file.h"
+#include "grabbag/picture.h"
+#include "grabbag/replaygain.h"
+#include "grabbag/seektable.h"
+
+#endif
diff --git a/include/share/grabbag/Makefile.am b/include/share/grabbag/Makefile.am
new file mode 100644 (file)
index 0000000..0d520aa
--- /dev/null
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = \
+       cuesheet.h \
+       file.h \
+       picture.h \
+       replaygain.h \
+       seektable.h
diff --git a/include/share/grabbag/cuesheet.h b/include/share/grabbag/cuesheet.h
new file mode 100644 (file)
index 0000000..698d49b
--- /dev/null
@@ -0,0 +1,42 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__CUESHEET_H
+#define GRABBAG__CUESHEET_H
+
+#include <stdio.h>
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames);
+void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames);
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/share/grabbag/file.h b/include/share/grabbag/file.h
new file mode 100644 (file)
index 0000000..c8b149f
--- /dev/null
@@ -0,0 +1,63 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* Convenience routines for manipulating files */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__FILE_H
+#define GRABAG__FILE_H
+
+/* needed because of off_t */
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h> /* for off_t */
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath);
+off_t grabbag__file_get_filesize(const char *srcpath);
+const char *grabbag__file_get_basename(const char *srcpath);
+
+/* read_only == false means "make file writable by user"
+ * read_only == true means "make file read-only for everyone"
+ */
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only);
+
+/* returns true iff stat() succeeds for both files and they have the same device and inode. */
+/* on windows, uses GetFileInformationByHandle() to compare */
+FLAC__bool grabbag__file_are_same(const char *f1, const char *f2);
+
+/* attempts to make writable before unlinking */
+FLAC__bool grabbag__file_remove_file(const char *filename);
+
+/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */
+FILE *grabbag__file_get_binary_stdin(void);
+FILE *grabbag__file_get_binary_stdout(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/share/grabbag/picture.h b/include/share/grabbag/picture.h
new file mode 100644 (file)
index 0000000..e7f4278
--- /dev/null
@@ -0,0 +1,46 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006,2007  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.
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__PICTURE_H
+#define GRABBAG__PICTURE_H
+
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* spec should be of the form "[TYPE]|MIME_TYPE|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE", e.g.
+ *   "|image/jpeg|||cover.jpg"
+ *   "4|image/jpeg||300x300x24|backcover.jpg"
+ *   "|image/png|description|300x300x24/71|cover.png"
+ *   "-->|image/gif||300x300x24/71|http://blah.blah.blah/cover.gif"
+ *
+ * empty type means default to FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER
+ * empty resolution spec means to get from the file (cannot get used with "-->" linked images)
+ * spec and error_message must not be NULL
+ */
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/share/grabbag/replaygain.h b/include/share/grabbag/replaygain.h
new file mode 100644 (file)
index 0000000..ea8c935
--- /dev/null
@@ -0,0 +1,72 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * This wraps the replaygain_analysis lib, which is LGPL.  This wrapper
+ * allows analysis of different input resolutions by automatically
+ * scaling the input signal
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__REPLAYGAIN_H
+#define GRABBAG__REPLAYGAIN_H
+
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
+
+/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples);
+
+void grabbag__replaygain_get_album(float *gain, float *peak);
+void grabbag__replaygain_get_title(float *gain, float *peak);
+
+/* These three functions return an error string on error, or NULL if successful */
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block);
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak);
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/share/grabbag/seektable.h b/include/share/grabbag/seektable.h
new file mode 100644 (file)
index 0000000..8010fc9
--- /dev/null
@@ -0,0 +1,38 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* Convenience routines for working with seek tables */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__SEEKTABLE_H
+#define GRABAG__SEEKTABLE_H
+
+#include "FLAC/format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/share/replaygain_analysis.h b/include/share/replaygain_analysis.h
new file mode 100644 (file)
index 0000000..02067d2
--- /dev/null
@@ -0,0 +1,59 @@
+/*\r
+ *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change\r
+ *  Copyright (C) 2001 David Robinson and Glen Sawyer\r
+ *\r
+ *  This library is free software; you can redistribute it and/or\r
+ *  modify it under the terms of the GNU Lesser General Public\r
+ *  License as published by the Free Software Foundation; either\r
+ *  version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ *  This library 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 GNU\r
+ *  Lesser General Public License for more details.\r
+ *\r
+ *  You should have received a copy of the GNU Lesser General Public\r
+ *  License along with this library; if not, write to the Free Software\r
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ *  concept and filter values by David Robinson (David@Robinson.org)\r
+ *    -- blame him if you think the idea is flawed\r
+ *  coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA\r
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed\r
+ *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson\r
+ *\r
+ *  For an explanation of the concepts and the basic algorithms involved, go to:\r
+ *    http://www.replaygain.org/\r
+ */\r
+\r
+#ifndef GAIN_ANALYSIS_H\r
+#define GAIN_ANALYSIS_H\r
+\r
+#include <stddef.h>\r
+\r
+#define GAIN_NOT_ENOUGH_SAMPLES  -24601\r
+#define GAIN_ANALYSIS_ERROR           0\r
+#define GAIN_ANALYSIS_OK              1\r
+\r
+#define INIT_GAIN_ANALYSIS_ERROR      0\r
+#define INIT_GAIN_ANALYSIS_OK         1\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+typedef float   Float_t;         /* Type used for filtering */\r
+\r
+extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */\r
+\r
+int     InitGainAnalysis ( long samplefreq );\r
+int     AnalyzeSamples   ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels );\r
+int            ResetSampleFrequency ( long samplefreq );\r
+Float_t GetTitleGain     ( void );\r
+Float_t GetAlbumGain     ( void );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* GAIN_ANALYSIS_H */\r
diff --git a/include/share/replaygain_synthesis.h b/include/share/replaygain_synthesis.h
new file mode 100644 (file)
index 0000000..ca1ae64
--- /dev/null
@@ -0,0 +1,51 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+
+#include <stdlib.h> /* for size_t */
+#include "FLAC/ordinals.h"
+
+#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2
+
+typedef enum {
+       NOISE_SHAPING_NONE = 0,
+       NOISE_SHAPING_LOW = 1,
+       NOISE_SHAPING_MEDIUM = 2,
+       NOISE_SHAPING_HIGH = 3
+} NoiseShaping;
+
+typedef struct {
+       const float*  FilterCoeff;
+       FLAC__uint64  Mask;
+       double        Add;
+       float         Dither;
+       float         ErrorHistory     [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];  /* 16th order Noise shaping */
+       float         DitherHistory    [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];
+       int           LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS];
+       unsigned      LastHistoryIndex;
+       NoiseShaping  ShapingType;
+} DitherContext;
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype);
+
+/* scale = (float) pow(10., (double)replaygain * 0.05); */
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
+
+#endif
diff --git a/include/share/utf8.h b/include/share/utf8.h
new file mode 100644 (file)
index 0000000..7d6650d
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SHARE__UTF8_H
+#define SHARE__UTF8_H
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ *  -1 : memory allocation failed
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ *   3 : unknown encoding (but still converted, using '?')
+ */
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#endif
diff --git a/include/test_libs_common/Makefile.am b/include/test_libs_common/Makefile.am
new file mode 100644 (file)
index 0000000..a0342dc
--- /dev/null
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = \
+       file_utils_flac.h \
+       metadata_utils.h
diff --git a/include/test_libs_common/file_utils_flac.h b/include/test_libs_common/file_utils_flac.h
new file mode 100644 (file)
index 0000000..27e3671
--- /dev/null
@@ -0,0 +1,34 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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
+
+/* needed because of off_t */
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/format.h"
+#include <sys/types.h> /* for off_t */
+
+extern const long file_utils__ogg_serial_number;
+
+FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, off_t *output_filesize, unsigned length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, unsigned num_metadata);
+
+#endif
diff --git a/include/test_libs_common/metadata_utils.h b/include/test_libs_common/metadata_utils.h
new file mode 100644 (file)
index 0000000..2f0f3ee
--- /dev/null
@@ -0,0 +1,70 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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_LIBS_COMMON_METADATA_UTILS_H
+#define FLAC__TEST_LIBS_COMMON_METADATA_UTILS_H
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#include "FLAC/format.h"
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy);
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy);
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy);
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy);
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy);
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy);
+
+void mutils__init_metadata_blocks(
+       FLAC__StreamMetadata *streaminfo,
+       FLAC__StreamMetadata *padding,
+       FLAC__StreamMetadata *seektable,
+       FLAC__StreamMetadata *application1,
+       FLAC__StreamMetadata *application2,
+       FLAC__StreamMetadata *vorbiscomment,
+       FLAC__StreamMetadata *cuesheet,
+       FLAC__StreamMetadata *picture,
+       FLAC__StreamMetadata *unknown
+);
+
+void mutils__free_metadata_blocks(
+       FLAC__StreamMetadata *streaminfo,
+       FLAC__StreamMetadata *padding,
+       FLAC__StreamMetadata *seektable,
+       FLAC__StreamMetadata *application1,
+       FLAC__StreamMetadata *application2,
+       FLAC__StreamMetadata *vorbiscomment,
+       FLAC__StreamMetadata *cuesheet,
+       FLAC__StreamMetadata *picture,
+       FLAC__StreamMetadata *unknown
+);
+
+#endif
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..6ce63b9
--- /dev/null
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd=$cpprog
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd=$stripprog
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "$0: no input file specified" >&2
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+
+       if [ -d "$dst" ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f "$src" ] || [ -d "$src" ]
+       then
+               :
+       else
+               echo "$0: $src does not exist" >&2
+               exit 1
+       fi
+
+       if [ x"$dst" = x ]
+       then
+               echo "$0: no destination specified" >&2
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d "$dst" ]
+       then
+               dst=$dst/`basename "$src"`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp=$pathcomp$1
+       shift
+
+       if [ ! -d "$pathcomp" ] ;
+        then
+               $mkdirprog "$pathcomp"
+       else
+               :
+       fi
+
+       pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd "$dst" &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               dstfile=`basename "$dst" $transformbasename |
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               :
+       fi
+
+# Make a couple of temp file names in the proper directory.
+
+       dsttmp=$dstdir/_inst.$$_
+       rmtmp=$dstdir/_rm.$$_
+
+# Trap to clean up temp files at exit.
+
+       trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+       trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location.  We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons.  In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+       if [ -f "$dstdir/$dstfile" ]
+       then
+               $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+               $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+               {
+                 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+                 (exit 1); exit
+               }
+       else
+               :
+       fi
+} &&
+
+# Now rename the file to the real destination.
+
+       $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+       (exit 0); exit
+}
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644 (file)
index 0000000..9be0eb1
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,6496 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.16
+TIMESTAMP=" (1.1220.2.235 2005/04/25 18:13:26)"
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes.
+if test -n "${ZSH_VERSION+set}" ; then
+  setopt NO_GLOB_SUBST
+fi
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell, and then maybe $echo will work.
+  exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo A|tr A '\301'` in
+ A) # EBCDIC based system
+  SP2NL="tr '\100' '\n'"
+  NL2SP="tr '\r\n' '\100\100'"
+  ;;
+ *) # Assume ASCII based system
+  SP2NL="tr '\040' '\012'"
+  NL2SP="tr '\015\012' '\040\040'"
+  ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+  save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+  save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS="  $lt_nl"
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+  $echo "$modename: not configured to build any kind of library" 1>&2
+  $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+quote_scanset='[[~#^*{};<>?'"'"'       ]'
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+      $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+      win32_nmres=`eval $NM -f posix -A $1 | \
+       sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
+      if test "X$win32_nmres" = "Ximport" ; then
+        win32_libid_type="x86 archive import"
+      else
+        win32_libid_type="x86 archive static"
+      fi
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+       case $arg in
+         *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+         arg="\"$arg\""
+         ;;
+       esac
+       CC_quoted="$CC_quoted $arg"
+      done
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+       for z in $available_tags; do
+         if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+           # Evaluate the configuration.
+           eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+           CC_quoted=
+           for arg in $CC; do
+           # Double-quote args containing other shell metacharacters.
+           case $arg in
+             *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+             arg="\"$arg\""
+             ;;
+           esac
+           CC_quoted="$CC_quoted $arg"
+         done
+           case "$@ " in
+             " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+             # The compiler in the base compile command matches
+             # the one in the tagged configuration.
+             # Assume this is the tagged configuration we want.
+             tagname=$z
+             break
+             ;;
+           esac
+         fi
+       done
+       # If $tagname still isn't set, then no tagged configuration
+       # was found and let the user know that the "--tag" command
+       # line option must be used.
+       if test -z "$tagname"; then
+         $echo "$modename: unable to infer tagged configuration"
+         $echo "$modename: specify a tag with \`--tag'" 1>&2
+         exit $EXIT_FAILURE
+#        else
+#          $echo "$modename: using $tagname tagged configuration"
+       fi
+       ;;
+      esac
+    fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+
+    $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
+    $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
+      exit $EXIT_FAILURE
+    fi
+}
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+    my_status=""
+
+    $show "${rm}r $my_gentop"
+    $run ${rm}r "$my_gentop"
+    $show "$mkdir $my_gentop"
+    $run $mkdir "$my_gentop"
+    my_status=$?
+    if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
+      exit $my_status
+    fi
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+       [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+       *) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
+      my_xdir="$my_gentop/$my_xlib"
+
+      $show "${rm}r $my_xdir"
+      $run ${rm}r "$my_xdir"
+      $show "$mkdir $my_xdir"
+      $run $mkdir "$my_xdir"
+      status=$?
+      if test "$status" -ne 0 && test ! -d "$my_xdir"; then
+       exit $status
+      fi
+      case $host in
+      *-darwin*)
+       $show "Extracting $my_xabs"
+       # Do not bother doing anything if just a dry run
+       if test -z "$run"; then
+         darwin_orig_dir=`pwd`
+         cd $my_xdir || exit $?
+         darwin_archive=$my_xabs
+         darwin_curdir=`pwd`
+         darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
+         darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
+         if test -n "$darwin_arches"; then 
+           darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
+           darwin_arch=
+           $show "$darwin_base_archive has multiple architectures $darwin_arches"
+           for darwin_arch in  $darwin_arches ; do
+             mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+             lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+             cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+             func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+             cd "$darwin_curdir"
+             $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+           done # $darwin_arches
+      ## Okay now we have a bunch of thin objects, gotta fatten them up :)
+           darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
+           darwin_file=
+           darwin_files=
+           for darwin_file in $darwin_filelist; do
+             darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+             lipo -create -output "$darwin_file" $darwin_files
+           done # $darwin_filelist
+           ${rm}r unfat-$$
+           cd "$darwin_orig_dir"
+         else
+           cd "$darwin_orig_dir"
+           func_extract_an_archive "$my_xdir" "$my_xabs"
+         fi # $darwin_arches
+       fi # $run
+      ;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+        ;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+    done
+    func_extract_archives_result="$my_oldobjs"
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+  arg="$1"
+  shift
+
+  case $arg in
+  -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    case $prev in
+    execute_dlfiles)
+      execute_dlfiles="$execute_dlfiles $arg"
+      ;;
+    tag)
+      tagname="$arg"
+      preserve_args="${preserve_args}=$arg"
+
+      # Check whether tagname contains only valid characters
+      case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+       $echo "$progname: invalid tag name: $tagname" 1>&2
+       exit $EXIT_FAILURE
+       ;;
+      esac
+
+      case $tagname in
+      CC)
+       # Don't test for the "default" C tag, as we know, it's there, but
+       # not specially marked.
+       ;;
+      *)
+       if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+         taglist="$taglist $tagname"
+         # Evaluate the configuration.
+         eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+       else
+         $echo "$progname: ignoring unknown tag $tagname" 1>&2
+       fi
+       ;;
+      esac
+      ;;
+    *)
+      eval "$prev=\$arg"
+      ;;
+    esac
+
+    prev=
+    prevopt=
+    continue
+  fi
+
+  # Have we seen a non-optional argument yet?
+  case $arg in
+  --help)
+    show_help=yes
+    ;;
+
+  --version)
+    $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+    $echo
+    $echo "Copyright (C) 2005  Free Software Foundation, Inc."
+    $echo "This is free software; see the source for copying conditions.  There is NO"
+    $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+    exit $?
+    ;;
+
+  --config)
+    ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+    done
+    exit $?
+    ;;
+
+  --debug)
+    $echo "$progname: enabling shell trace mode"
+    set -x
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --dry-run | -n)
+    run=:
+    ;;
+
+  --features)
+    $echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      $echo "enable shared libraries"
+    else
+      $echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      $echo "enable static libraries"
+    else
+      $echo "disable static libraries"
+    fi
+    exit $?
+    ;;
+
+  --finish) mode="finish" ;;
+
+  --mode) prevopt="--mode" prev=mode ;;
+  --mode=*) mode="$optarg" ;;
+
+  --preserve-dup-deps) duplicate_deps="yes" ;;
+
+  --quiet | --silent)
+    show=:
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --tag) prevopt="--tag" prev=tag ;;
+  --tag=*)
+    set tag "$optarg" ${1+"$@"}
+    shift
+    prev=tag
+    preserve_args="$preserve_args --tag"
+    ;;
+
+  -dlopen)
+    prevopt="-dlopen"
+    prev=execute_dlfiles
+    ;;
+
+  -*)
+    $echo "$modename: unrecognized option \`$arg'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+
+  *)
+    nonopt="$arg"
+    break
+    ;;
+  esac
+done
+
+if test -n "$prevopt"; then
+  $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+  # Infer the operation mode.
+  if test -z "$mode"; then
+    $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+    $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
+    case $nonopt in
+    *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+      mode=link
+      for arg
+      do
+       case $arg in
+       -c)
+          mode=compile
+          break
+          ;;
+       esac
+      done
+      ;;
+    *db | *dbx | *strace | *truss)
+      mode=execute
+      ;;
+    *install*|cp|mv)
+      mode=install
+      ;;
+    *rm)
+      mode=uninstall
+      ;;
+    *)
+      # If we have no mode, but dlfiles were specified, then do execute mode.
+      test -n "$execute_dlfiles" && mode=execute
+
+      # Just use the default operation mode.
+      if test -z "$mode"; then
+       if test -n "$nonopt"; then
+         $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+       else
+         $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+       fi
+      fi
+      ;;
+    esac
+  fi
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$modename --help --mode=$mode' for more information."
+
+  # These modes are in order of execution frequency so that they run quickly.
+  case $mode in
+  # libtool compile mode
+  compile)
+    modename="$modename: compile"
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+
+    for arg
+    do
+      case "$arg_mode" in
+      arg  )
+       # do not "continue".  Instead, add this to base_compile
+       lastarg="$arg"
+       arg_mode=normal
+       ;;
+
+      target )
+       libobj="$arg"
+       arg_mode=normal
+       continue
+       ;;
+
+      normal )
+       # Accept any command-line options.
+       case $arg in
+       -o)
+         if test -n "$libobj" ; then
+           $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+           exit $EXIT_FAILURE
+         fi
+         arg_mode=target
+         continue
+         ;;
+
+       -static | -prefer-pic | -prefer-non-pic)
+         later="$later $arg"
+         continue
+         ;;
+
+       -no-suppress)
+         suppress_opt=no
+         continue
+         ;;
+
+       -Xcompiler)
+         arg_mode=arg  #  the next one goes into the "base_compile" arg list
+         continue      #  The current "srcfile" will either be retained or
+         ;;            #  replaced later.  I would guess that would be a bug.
+
+       -Wc,*)
+         args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+         lastarg=
+         save_ifs="$IFS"; IFS=','
+         for arg in $args; do
+           IFS="$save_ifs"
+
+           # Double-quote args containing other shell metacharacters.
+           # Many Bourne shells cannot handle close brackets correctly
+           # in scan sets, so we specify it separately.
+           case $arg in
+             *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+             arg="\"$arg\""
+             ;;
+           esac
+           lastarg="$lastarg $arg"
+         done
+         IFS="$save_ifs"
+         lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+         # Add the arguments to base_compile.
+         base_compile="$base_compile $lastarg"
+         continue
+         ;;
+
+       * )
+         # Accept the current argument as the source file.
+         # The previous "srcfile" becomes the current argument.
+         #
+         lastarg="$srcfile"
+         srcfile="$arg"
+         ;;
+       esac  #  case $arg
+       ;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+      case $lastarg in
+      # Double-quote args containing other shell metacharacters.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, and some SunOS ksh mistreat backslash-escaping
+      # in scan sets (worked around with variable expansion),
+      # and furthermore cannot handle '|' '&' '(' ')' in scan sets 
+      # at all, so we specify them separately.
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+       lastarg="\"$lastarg\""
+       ;;
+      esac
+
+      base_compile="$base_compile $lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      $echo "$modename: you must specify an argument for -Xcompile"
+      exit $EXIT_FAILURE
+      ;;
+    target)
+      $echo "$modename: you must specify a target with \`-o'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *)
+      # Get the name of the library object.
+      [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    xform='[cCFSifmso]'
+    case $libobj in
+    *.ada) xform=ada ;;
+    *.adb) xform=adb ;;
+    *.ads) xform=ads ;;
+    *.asm) xform=asm ;;
+    *.c++) xform=c++ ;;
+    *.cc) xform=cc ;;
+    *.ii) xform=ii ;;
+    *.class) xform=class ;;
+    *.cpp) xform=cpp ;;
+    *.cxx) xform=cxx ;;
+    *.f90) xform=f90 ;;
+    *.for) xform=for ;;
+    *.java) xform=java ;;
+    esac
+
+    libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+    case $libobj in
+    *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+    *)
+      $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -static)
+       build_old_libs=yes
+       continue
+       ;;
+
+      -prefer-pic)
+       pic_mode=yes
+       continue
+       ;;
+
+      -prefer-non-pic)
+       pic_mode=no
+       continue
+       ;;
+      esac
+    done
+
+    qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
+    case $qlibobj in
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+       qlibobj="\"$qlibobj\"" ;;
+    esac
+    if test "X$libobj" != "X$qlibobj"; then
+       $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
+       exit $EXIT_FAILURE
+    fi
+    objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+    xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$xdir" = "X$obj"; then
+      xdir=
+    else
+      xdir=$xdir/
+    fi
+    lobj=${xdir}$objdir/$objname
+
+    if test -z "$base_compile"; then
+      $echo "$modename: you must specify a compilation command" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    $run $rm $removelist
+    trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+      removelist="$removelist $output_obj $lockfile"
+      trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+       $show "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+       $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit $EXIT_FAILURE
+      fi
+      $echo "$srcfile" > "$lockfile"
+    fi
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+    qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
+    case $qsrcfile in
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+      qsrcfile="\"$qsrcfile\"" ;;
+    esac
+
+    $run $rm "$libobj" "${libobj}T"
+
+    # Create a libtool object file (analogous to a ".la" file),
+    # but don't create it if we're doing a dry run.
+    test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+       command="$base_compile $qsrcfile $pic_flag"
+      else
+       # Don't build PIC code
+       command="$base_compile $qsrcfile"
+      fi
+
+      if test ! -d "${xdir}$objdir"; then
+       $show "$mkdir ${xdir}$objdir"
+       $run $mkdir ${xdir}$objdir
+       status=$?
+       if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then
+         exit $status
+       fi
+      fi
+
+      if test -z "$output_obj"; then
+       # Place PIC objects in $objdir
+       command="$command -o $lobj"
+      fi
+
+      $run $rm "$lobj" "$output_obj"
+
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+       test -n "$output_obj" && $run $rm $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+       $show "$mv $output_obj $lobj"
+       if $run $mv $output_obj $lobj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+
+      # Append the name of the PIC object to the libtool object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+        suppress_output=' >/dev/null 2>&1'
+      fi
+    else
+      # No PIC object so indicate it doesn't exist in the libtool
+      # object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+       # Don't build PIC code
+       command="$base_compile $qsrcfile"
+      else
+       command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+       command="$command -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      $run $rm "$obj" "$output_obj"
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+       $run $rm $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+       $show "$mv $output_obj $obj"
+       if $run $mv $output_obj $obj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+    else
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+    fi
+
+    $run $mv "${libobj}T" "${libobj}"
+
+    # Unlock the critical section if it was locked
+    if test "$need_locks" != no; then
+      $run $rm "$lockfile"
+    fi
+
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool link mode
+  link | relink)
+    modename="$modename: link"
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args="$nonopt"
+    base_compile="$nonopt $@"
+    compile_command="$nonopt"
+    finalize_command="$nonopt"
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+
+    avoid_version=no
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -all-static | -static)
+       if test "X$arg" = "X-all-static"; then
+         if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+           $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+         fi
+         if test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+       else
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+       fi
+       build_libtool_libs=no
+       build_old_libs=yes
+       prefer_static_libs=yes
+       break
+       ;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      case $arg in
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+       qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+       ;;
+      *) qarg=$arg ;;
+      esac
+      libtool_args="$libtool_args $qarg"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+       case $prev in
+       output)
+         compile_command="$compile_command @OUTPUT@"
+         finalize_command="$finalize_command @OUTPUT@"
+         ;;
+       esac
+
+       case $prev in
+       dlfiles|dlprefiles)
+         if test "$preload" = no; then
+           # Add the symbol object into the linking commands.
+           compile_command="$compile_command @SYMFILE@"
+           finalize_command="$finalize_command @SYMFILE@"
+           preload=yes
+         fi
+         case $arg in
+         *.la | *.lo) ;;  # We handle these cases below.
+         force)
+           if test "$dlself" = no; then
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         self)
+           if test "$prev" = dlprefiles; then
+             dlself=yes
+           elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+             dlself=yes
+           else
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         *)
+           if test "$prev" = dlfiles; then
+             dlfiles="$dlfiles $arg"
+           else
+             dlprefiles="$dlprefiles $arg"
+           fi
+           prev=
+           continue
+           ;;
+         esac
+         ;;
+       expsyms)
+         export_symbols="$arg"
+         if test ! -f "$arg"; then
+           $echo "$modename: symbol file \`$arg' does not exist"
+           exit $EXIT_FAILURE
+         fi
+         prev=
+         continue
+         ;;
+       expsyms_regex)
+         export_symbols_regex="$arg"
+         prev=
+         continue
+         ;;
+       inst_prefix)
+         inst_prefix_dir="$arg"
+         prev=
+         continue
+         ;;
+       precious_regex)
+         precious_files_regex="$arg"
+         prev=
+         continue
+         ;;
+       release)
+         release="-$arg"
+         prev=
+         continue
+         ;;
+       objectlist)
+         if test -f "$arg"; then
+           save_arg=$arg
+           moreargs=
+           for fil in `cat $save_arg`
+           do
+#            moreargs="$moreargs $fil"
+             arg=$fil
+             # A libtool-controlled object.
+
+             # Check to see that this really is a libtool object.
+             if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+               pic_object=
+               non_pic_object=
+
+               # Read the .lo file
+               # If there is no directory component, then add one.
+               case $arg in
+               */* | *\\*) . $arg ;;
+               *) . ./$arg ;;
+               esac
+
+               if test -z "$pic_object" || \
+                  test -z "$non_pic_object" ||
+                  test "$pic_object" = none && \
+                  test "$non_pic_object" = none; then
+                 $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+                 exit $EXIT_FAILURE
+               fi
+
+               # Extract subdirectory from the argument.
+               xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+               if test "X$xdir" = "X$arg"; then
+                 xdir=
+               else
+                 xdir="$xdir/"
+               fi
+
+               if test "$pic_object" != none; then
+                 # Prepend the subdirectory the object is found in.
+                 pic_object="$xdir$pic_object"
+
+                 if test "$prev" = dlfiles; then
+                   if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+                     dlfiles="$dlfiles $pic_object"
+                     prev=
+                     continue
+                   else
+                     # If libtool objects are unsupported, then we need to preload.
+                     prev=dlprefiles
+                   fi
+                 fi
+
+                 # CHECK ME:  I think I busted this.  -Ossama
+                 if test "$prev" = dlprefiles; then
+                   # Preload the old-style object.
+                   dlprefiles="$dlprefiles $pic_object"
+                   prev=
+                 fi
+
+                 # A PIC object.
+                 libobjs="$libobjs $pic_object"
+                 arg="$pic_object"
+               fi
+
+               # Non-PIC object.
+               if test "$non_pic_object" != none; then
+                 # Prepend the subdirectory the object is found in.
+                 non_pic_object="$xdir$non_pic_object"
+
+                 # A standard non-PIC object
+                 non_pic_objects="$non_pic_objects $non_pic_object"
+                 if test -z "$pic_object" || test "$pic_object" = none ; then
+                   arg="$non_pic_object"
+                 fi
+               fi
+             else
+               # Only an error if not doing a dry-run.
+               if test -z "$run"; then
+                 $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+                 exit $EXIT_FAILURE
+               else
+                 # Dry-run case.
+
+                 # Extract subdirectory from the argument.
+                 xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+                 if test "X$xdir" = "X$arg"; then
+                   xdir=
+                 else
+                   xdir="$xdir/"
+                 fi
+
+                 pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+                 non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+                 libobjs="$libobjs $pic_object"
+                 non_pic_objects="$non_pic_objects $non_pic_object"
+               fi
+             fi
+           done
+         else
+           $echo "$modename: link input file \`$save_arg' does not exist"
+           exit $EXIT_FAILURE
+         fi
+         arg=$save_arg
+         prev=
+         continue
+         ;;
+       rpath | xrpath)
+         # We need an absolute path.
+         case $arg in
+         [\\/]* | [A-Za-z]:[\\/]*) ;;
+         *)
+           $echo "$modename: only absolute run-paths are allowed" 1>&2
+           exit $EXIT_FAILURE
+           ;;
+         esac
+         if test "$prev" = rpath; then
+           case "$rpath " in
+           *" $arg "*) ;;
+           *) rpath="$rpath $arg" ;;
+           esac
+         else
+           case "$xrpath " in
+           *" $arg "*) ;;
+           *) xrpath="$xrpath $arg" ;;
+           esac
+         fi
+         prev=
+         continue
+         ;;
+       xcompiler)
+         compiler_flags="$compiler_flags $qarg"
+         prev=
+         compile_command="$compile_command $qarg"
+         finalize_command="$finalize_command $qarg"
+         continue
+         ;;
+       xlinker)
+         linker_flags="$linker_flags $qarg"
+         compiler_flags="$compiler_flags $wl$qarg"
+         prev=
+         compile_command="$compile_command $wl$qarg"
+         finalize_command="$finalize_command $wl$qarg"
+         continue
+         ;;
+       xcclinker)
+         linker_flags="$linker_flags $qarg"
+         compiler_flags="$compiler_flags $qarg"
+         prev=
+         compile_command="$compile_command $qarg"
+         finalize_command="$finalize_command $qarg"
+         continue
+         ;;
+       shrext)
+         shrext_cmds="$arg"
+         prev=
+         continue
+         ;;
+        darwin_framework)
+         compiler_flags="$compiler_flags $arg"
+         prev=
+         continue
+         ;;
+       *)
+         eval "$prev=\"\$arg\""
+         prev=
+         continue
+         ;;
+       esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+       if test -n "$link_static_flag"; then
+         compile_command="$compile_command $link_static_flag"
+         finalize_command="$finalize_command $link_static_flag"
+       fi
+       continue
+       ;;
+
+      -allow-undefined)
+       # FIXME: remove this flag sometime in the future.
+       $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+       continue
+       ;;
+
+      -avoid-version)
+       avoid_version=yes
+       continue
+       ;;
+
+      -dlopen)
+       prev=dlfiles
+       continue
+       ;;
+
+      -dlpreopen)
+       prev=dlprefiles
+       continue
+       ;;
+
+      -export-dynamic)
+       export_dynamic=yes
+       continue
+       ;;
+
+      -export-symbols | -export-symbols-regex)
+       if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+         $echo "$modename: more than one -exported-symbols argument is not allowed"
+         exit $EXIT_FAILURE
+       fi
+       if test "X$arg" = "X-export-symbols"; then
+         prev=expsyms
+       else
+         prev=expsyms_regex
+       fi
+       continue
+       ;;
+
+      -framework)
+        prev=darwin_framework
+        compiler_flags="$compiler_flags $arg"
+        continue
+        ;;
+
+      -inst-prefix-dir)
+       prev=inst_prefix
+       continue
+       ;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+       case $with_gcc/$host in
+       no/*-*-irix* | /*-*-irix*)
+         compile_command="$compile_command $arg"
+         finalize_command="$finalize_command $arg"
+         ;;
+       esac
+       continue
+       ;;
+
+      -L*)
+       dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         absdir=`cd "$dir" && pwd`
+         if test -z "$absdir"; then
+           $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+           exit $EXIT_FAILURE
+         fi
+         dir="$absdir"
+         ;;
+       esac
+       case "$deplibs " in
+       *" -L$dir "*) ;;
+       *)
+         deplibs="$deplibs -L$dir"
+         lib_search_path="$lib_search_path $dir"
+         ;;
+       esac
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+         case :$dllsearchpath: in
+         *":$dir:"*) ;;
+         *) dllsearchpath="$dllsearchpath:$dir";;
+         esac
+         ;;
+       esac
+       continue
+       ;;
+
+      -l*)
+       if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+         case $host in
+         *-*-cygwin* | *-*-pw32* | *-*-beos*)
+           # These systems don't actually have a C or math library (as such)
+           continue
+           ;;
+         *-*-mingw* | *-*-os2*)
+           # These systems don't actually have a C library (as such)
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+           # Do not include libc due to us having libc/libc_r.
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C and math libraries are in the System framework
+           deplibs="$deplibs -framework System"
+           continue
+         esac
+       elif test "X$arg" = "X-lc_r"; then
+        case $host in
+        *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+          # Do not include libc_r directly, use -pthread flag.
+          continue
+          ;;
+        esac
+       fi
+       deplibs="$deplibs $arg"
+       continue
+       ;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      -model)
+       compile_command="$compile_command $arg"
+       compiler_flags="$compiler_flags $arg"
+       finalize_command="$finalize_command $arg"
+       prev=xcompiler
+       continue
+       ;;
+
+     -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+       compiler_flags="$compiler_flags $arg"
+       compile_command="$compile_command $arg"
+       finalize_command="$finalize_command $arg"
+       continue
+       ;;
+
+      -module)
+       module=yes
+       continue
+       ;;
+
+      # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+      # -r[0-9][0-9]* specifies the processor on the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+      # +DA*, +DD* enable 64-bit mode on the HP compiler
+      # -q* pass through compiler args for the IBM compiler
+      # -m* pass through architecture-specific compiler args for GCC
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*)
+
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case $arg in
+       *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+         arg="\"$arg\""
+         ;;
+       esac
+        compile_command="$compile_command $arg"
+        finalize_command="$finalize_command $arg"
+        if test "$with_gcc" = "yes" ; then
+          compiler_flags="$compiler_flags $arg"
+        fi
+        continue
+        ;;
+
+      -shrext)
+       prev=shrext
+       continue
+       ;;
+
+      -no-fast-install)
+       fast_install=no
+       continue
+       ;;
+
+      -no-install)
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+         # The PATH hackery in wrapper scripts is required on Windows
+         # in order for the loader to find any dlls it needs.
+         $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+         $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+         fast_install=no
+         ;;
+       *) no_install=yes ;;
+       esac
+       continue
+       ;;
+
+      -no-undefined)
+       allow_undefined=no
+       continue
+       ;;
+
+      -objectlist)
+       prev=objectlist
+       continue
+       ;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+       prev=precious_regex
+       continue
+       ;;
+
+      -release)
+       prev=release
+       continue
+       ;;
+
+      -rpath)
+       prev=rpath
+       continue
+       ;;
+
+      -R)
+       prev=xrpath
+       continue
+       ;;
+
+      -R*)
+       dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         $echo "$modename: only absolute run-paths are allowed" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+       case "$xrpath " in
+       *" $dir "*) ;;
+       *) xrpath="$xrpath $dir" ;;
+       esac
+       continue
+       ;;
+
+      -static)
+       # The effects of -static are defined in a previous loop.
+       # We used to do the same as -all-static on platforms that
+       # didn't have a PIC flag, but the assumption that the effects
+       # would be equivalent was wrong.  It would break on at least
+       # Digital Unix and AIX.
+       continue
+       ;;
+
+      -thread-safe)
+       thread_safe=yes
+       continue
+       ;;
+
+      -version-info)
+       prev=vinfo
+       continue
+       ;;
+      -version-number)
+       prev=vinfo
+       vinfo_number=yes
+       continue
+       ;;
+
+      -Wc,*)
+       args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+       arg=
+       save_ifs="$IFS"; IFS=','
+       for flag in $args; do
+         IFS="$save_ifs"
+         case $flag in
+           *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+           flag="\"$flag\""
+           ;;
+         esac
+         arg="$arg $wl$flag"
+         compiler_flags="$compiler_flags $flag"
+       done
+       IFS="$save_ifs"
+       arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+       ;;
+
+      -Wl,*)
+       args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+       arg=
+       save_ifs="$IFS"; IFS=','
+       for flag in $args; do
+         IFS="$save_ifs"
+         case $flag in
+           *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+           flag="\"$flag\""
+           ;;
+         esac
+         arg="$arg $wl$flag"
+         compiler_flags="$compiler_flags $wl$flag"
+         linker_flags="$linker_flags $flag"
+       done
+       IFS="$save_ifs"
+       arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+       ;;
+
+      -Xcompiler)
+       prev=xcompiler
+       continue
+       ;;
+
+      -Xlinker)
+       prev=xlinker
+       continue
+       ;;
+
+      -XCClinker)
+       prev=xcclinker
+       continue
+       ;;
+
+      # Some other compiler flag.
+      -* | +*)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case $arg in
+       *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+         arg="\"$arg\""
+         ;;
+       esac
+       ;;
+
+      *.$objext)
+       # A standard object.
+       objs="$objs $arg"
+       ;;
+
+      *.lo)
+       # A libtool-controlled object.
+
+       # Check to see that this really is a libtool object.
+       if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         pic_object=
+         non_pic_object=
+
+         # Read the .lo file
+         # If there is no directory component, then add one.
+         case $arg in
+         */* | *\\*) . $arg ;;
+         *) . ./$arg ;;
+         esac
+
+         if test -z "$pic_object" || \
+            test -z "$non_pic_object" ||
+            test "$pic_object" = none && \
+            test "$non_pic_object" = none; then
+           $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+           exit $EXIT_FAILURE
+         fi
+
+         # Extract subdirectory from the argument.
+         xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+         if test "X$xdir" = "X$arg"; then
+           xdir=
+         else
+           xdir="$xdir/"
+         fi
+
+         if test "$pic_object" != none; then
+           # Prepend the subdirectory the object is found in.
+           pic_object="$xdir$pic_object"
+
+           if test "$prev" = dlfiles; then
+             if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+               dlfiles="$dlfiles $pic_object"
+               prev=
+               continue
+             else
+               # If libtool objects are unsupported, then we need to preload.
+               prev=dlprefiles
+             fi
+           fi
+
+           # CHECK ME:  I think I busted this.  -Ossama
+           if test "$prev" = dlprefiles; then
+             # Preload the old-style object.
+             dlprefiles="$dlprefiles $pic_object"
+             prev=
+           fi
+
+           # A PIC object.
+           libobjs="$libobjs $pic_object"
+           arg="$pic_object"
+         fi
+
+         # Non-PIC object.
+         if test "$non_pic_object" != none; then
+           # Prepend the subdirectory the object is found in.
+           non_pic_object="$xdir$non_pic_object"
+
+           # A standard non-PIC object
+           non_pic_objects="$non_pic_objects $non_pic_object"
+           if test -z "$pic_object" || test "$pic_object" = none ; then
+             arg="$non_pic_object"
+           fi
+         fi
+       else
+         # Only an error if not doing a dry-run.
+         if test -z "$run"; then
+           $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+           exit $EXIT_FAILURE
+         else
+           # Dry-run case.
+
+           # Extract subdirectory from the argument.
+           xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+           if test "X$xdir" = "X$arg"; then
+             xdir=
+           else
+             xdir="$xdir/"
+           fi
+
+           pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+           non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+           libobjs="$libobjs $pic_object"
+           non_pic_objects="$non_pic_objects $non_pic_object"
+         fi
+       fi
+       ;;
+
+      *.$libext)
+       # An archive.
+       deplibs="$deplibs $arg"
+       old_deplibs="$old_deplibs $arg"
+       continue
+       ;;
+
+      *.la)
+       # A libtool-controlled library.
+
+       if test "$prev" = dlfiles; then
+         # This library was specified with -dlopen.
+         dlfiles="$dlfiles $arg"
+         prev=
+       elif test "$prev" = dlprefiles; then
+         # The library was specified with -dlpreopen.
+         dlprefiles="$dlprefiles $arg"
+         prev=
+       else
+         deplibs="$deplibs $arg"
+       fi
+       continue
+       ;;
+
+      # Some other compiler argument.
+      *)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case $arg in
+       *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+         arg="\"$arg\""
+         ;;
+       esac
+       ;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+       compile_command="$compile_command $arg"
+       finalize_command="$finalize_command $arg"
+      fi
+    done # argument parsing loop
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      compile_command="$compile_command $arg"
+      finalize_command="$finalize_command $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$output_objdir" = "X$output"; then
+      output_objdir="$objdir"
+    else
+      output_objdir="$output_objdir/$objdir"
+    fi
+    # Create the object directory.
+    if test ! -d "$output_objdir"; then
+      $show "$mkdir $output_objdir"
+      $run $mkdir $output_objdir
+      status=$?
+      if test "$status" -ne 0 && test ! -d "$output_objdir"; then
+       exit $status
+      fi
+    fi
+
+    # Determine the type of output
+    case $output in
+    "")
+      $echo "$modename: you must specify an output file" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    case $host in
+    *cygwin* | *mingw* | *pw32*)
+      # don't eliminate duplications in $postdeps and $predeps
+      duplicate_compiler_generated_deps=yes
+      ;;
+    *)
+      duplicate_compiler_generated_deps=$duplicate_deps
+      ;;
+    esac
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if test "X$duplicate_deps" = "Xyes" ; then
+       case "$libs " in
+       *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+       esac
+      fi
+      libs="$libs $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+       for pre_post_dep in $predeps $postdeps; do
+         case "$pre_post_deps " in
+         *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+         esac
+         pre_post_deps="$pre_post_deps $pre_post_dep"
+       done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+    case $linkmode in
+    lib)
+       passes="conv link"
+       for file in $dlfiles $dlprefiles; do
+         case $file in
+         *.la) ;;
+         *)
+           $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+           exit $EXIT_FAILURE
+           ;;
+         esac
+       done
+       ;;
+    prog)
+       compile_deplibs=
+       finalize_deplibs=
+       alldeplibs=no
+       newdlfiles=
+       newdlprefiles=
+       passes="conv scan dlopen dlpreopen link"
+       ;;
+    *)  passes="conv"
+       ;;
+    esac
+    for pass in $passes; do
+      if test "$linkmode,$pass" = "lib,link" ||
+        test "$linkmode,$pass" = "prog,scan"; then
+       libs="$deplibs"
+       deplibs=
+      fi
+      if test "$linkmode" = prog; then
+       case $pass in
+       dlopen) libs="$dlfiles" ;;
+       dlpreopen) libs="$dlprefiles" ;;
+       link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+       esac
+      fi
+      if test "$pass" = dlopen; then
+       # Collect dlpreopened libraries
+       save_deplibs="$deplibs"
+       deplibs=
+      fi
+      for deplib in $libs; do
+       lib=
+       found=no
+       case $deplib in
+       -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+         if test "$linkmode,$pass" = "prog,link"; then
+           compile_deplibs="$deplib $compile_deplibs"
+           finalize_deplibs="$deplib $finalize_deplibs"
+         else
+           compiler_flags="$compiler_flags $deplib"
+         fi
+         continue
+         ;;
+       -l*)
+         if test "$linkmode" != lib && test "$linkmode" != prog; then
+           $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+           continue
+         fi
+         name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+         for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+           for search_ext in .la $std_shrext .so .a; do
+             # Search the libtool library
+             lib="$searchdir/lib${name}${search_ext}"
+             if test -f "$lib"; then
+               if test "$search_ext" = ".la"; then
+                 found=yes
+               else
+                 found=no
+               fi
+               break 2
+             fi
+           done
+         done
+         if test "$found" != yes; then
+           # deplib doesn't seem to be a libtool library
+           if test "$linkmode,$pass" = "prog,link"; then
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             deplibs="$deplib $deplibs"
+             test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+           fi
+           continue
+         else # deplib is a libtool library
+           # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+           # We need to do some special things here, and not later.
+           if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+             case " $predeps $postdeps " in
+             *" $deplib "*)
+               if (${SED} -e '2q' $lib |
+                    grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+                 library_names=
+                 old_library=
+                 case $lib in
+                 */* | *\\*) . $lib ;;
+                 *) . ./$lib ;;
+                 esac
+                 for l in $old_library $library_names; do
+                   ll="$l"
+                 done
+                 if test "X$ll" = "X$old_library" ; then # only static version available
+                   found=no
+                   ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+                   test "X$ladir" = "X$lib" && ladir="."
+                   lib=$ladir/$old_library
+                   if test "$linkmode,$pass" = "prog,link"; then
+                     compile_deplibs="$deplib $compile_deplibs"
+                     finalize_deplibs="$deplib $finalize_deplibs"
+                   else
+                     deplibs="$deplib $deplibs"
+                     test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+                   fi
+                   continue
+                 fi
+               fi
+               ;;
+             *) ;;
+             esac
+           fi
+         fi
+         ;; # -l
+       -L*)
+         case $linkmode in
+         lib)
+           deplibs="$deplib $deplibs"
+           test "$pass" = conv && continue
+           newdependency_libs="$deplib $newdependency_libs"
+           newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+           ;;
+         prog)
+           if test "$pass" = conv; then
+             deplibs="$deplib $deplibs"
+             continue
+           fi
+           if test "$pass" = scan; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+           ;;
+         *)
+           $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+           ;;
+         esac # linkmode
+         continue
+         ;; # -L
+       -R*)
+         if test "$pass" = link; then
+           dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+           # Make sure the xrpath contains only unique directories.
+           case "$xrpath " in
+           *" $dir "*) ;;
+           *) xrpath="$xrpath $dir" ;;
+           esac
+         fi
+         deplibs="$deplib $deplibs"
+         continue
+         ;;
+       *.la) lib="$deplib" ;;
+       *.$libext)
+         if test "$pass" = conv; then
+           deplibs="$deplib $deplibs"
+           continue
+         fi
+         case $linkmode in
+         lib)
+           valid_a_lib=no
+           case $deplibs_check_method in
+             match_pattern*)
+               set dummy $deplibs_check_method
+               match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+               if eval $echo \"$deplib\" 2>/dev/null \
+                   | $SED 10q \
+                   | $EGREP "$match_pattern_regex" > /dev/null; then
+                 valid_a_lib=yes
+               fi
+               ;;
+             pass_all)
+               valid_a_lib=yes
+               ;;
+            esac
+           if test "$valid_a_lib" != yes; then
+             $echo
+             $echo "*** Warning: Trying to link with static lib archive $deplib."
+             $echo "*** I have the capability to make that library automatically link in when"
+             $echo "*** you link to this library.  But I can only do this if you have a"
+             $echo "*** shared version of the library, which you do not appear to have"
+             $echo "*** because the file extensions .$libext of this argument makes me believe"
+             $echo "*** that it is just a static archive that I should not used here."
+           else
+             $echo
+             $echo "*** Warning: Linking the shared library $output against the"
+             $echo "*** static library $deplib is not portable!"
+             deplibs="$deplib $deplibs"
+           fi
+           continue
+           ;;
+         prog)
+           if test "$pass" != link; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           continue
+           ;;
+         esac # linkmode
+         ;; # *.$libext
+       *.lo | *.$objext)
+         if test "$pass" = conv; then
+           deplibs="$deplib $deplibs"
+         elif test "$linkmode" = prog; then
+           if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+             # If there is no dlopen support or we're linking statically,
+             # we need to preload.
+             newdlprefiles="$newdlprefiles $deplib"
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             newdlfiles="$newdlfiles $deplib"
+           fi
+         fi
+         continue
+         ;;
+       %DEPLIBS%)
+         alldeplibs=yes
+         continue
+         ;;
+       esac # case $deplib
+       if test "$found" = yes || test -f "$lib"; then :
+       else
+         $echo "$modename: cannot find the library \`$lib'" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       # Check to see that this really is a libtool archive.
+       if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$ladir" = "X$lib" && ladir="."
+
+       dlname=
+       dlopen=
+       dlpreopen=
+       libdir=
+       library_names=
+       old_library=
+       # If the library was installed with an old release of libtool,
+       # it will not redefine variables installed, or shouldnotlink
+       installed=yes
+       shouldnotlink=no
+       avoidtemprpath=
+
+
+       # Read the .la file
+       case $lib in
+       */* | *\\*) . $lib ;;
+       *) . ./$lib ;;
+       esac
+
+       if test "$linkmode,$pass" = "lib,link" ||
+          test "$linkmode,$pass" = "prog,scan" ||
+          { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+         test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+         test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+       fi
+
+       if test "$pass" = conv; then
+         # Only check for convenience libraries
+         deplibs="$lib $deplibs"
+         if test -z "$libdir"; then
+           if test -z "$old_library"; then
+             $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+             exit $EXIT_FAILURE
+           fi
+           # It is a libtool convenience library, so add in its objects.
+           convenience="$convenience $ladir/$objdir/$old_library"
+           old_convenience="$old_convenience $ladir/$objdir/$old_library"
+           tmp_libs=
+           for deplib in $dependency_libs; do
+             deplibs="$deplib $deplibs"
+              if test "X$duplicate_deps" = "Xyes" ; then
+               case "$tmp_libs " in
+               *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+               esac
+              fi
+             tmp_libs="$tmp_libs $deplib"
+           done
+         elif test "$linkmode" != prog && test "$linkmode" != lib; then
+           $echo "$modename: \`$lib' is not a convenience library" 1>&2
+           exit $EXIT_FAILURE
+         fi
+         continue
+       fi # $pass = conv
+
+
+       # Get the name of the library we link against.
+       linklib=
+       for l in $old_library $library_names; do
+         linklib="$l"
+       done
+       if test -z "$linklib"; then
+         $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       # This library was specified with -dlopen.
+       if test "$pass" = dlopen; then
+         if test -z "$libdir"; then
+           $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+           exit $EXIT_FAILURE
+         fi
+         if test -z "$dlname" ||
+            test "$dlopen_support" != yes ||
+            test "$build_libtool_libs" = no; then
+           # If there is no dlname, no dlopen support or we're linking
+           # statically, we need to preload.  We also need to preload any
+           # dependent libraries so libltdl's deplib preloader doesn't
+           # bomb out in the load deplibs phase.
+           dlprefiles="$dlprefiles $lib $dependency_libs"
+         else
+           newdlfiles="$newdlfiles $lib"
+         fi
+         continue
+       fi # $pass = dlopen
+
+       # We need an absolute path.
+       case $ladir in
+       [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+       *)
+         abs_ladir=`cd "$ladir" && pwd`
+         if test -z "$abs_ladir"; then
+           $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+           $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+           abs_ladir="$ladir"
+         fi
+         ;;
+       esac
+       laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+       # Find the relevant object directory and library name.
+       if test "X$installed" = Xyes; then
+         if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           $echo "$modename: warning: library \`$lib' was moved." 1>&2
+           dir="$ladir"
+           absdir="$abs_ladir"
+           libdir="$abs_ladir"
+         else
+           dir="$libdir"
+           absdir="$libdir"
+         fi
+         test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+       else
+         if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           dir="$ladir"
+           absdir="$abs_ladir"
+           # Remove this search path later
+           notinst_path="$notinst_path $abs_ladir"
+         else
+           dir="$ladir/$objdir"
+           absdir="$abs_ladir/$objdir"
+           # Remove this search path later
+           notinst_path="$notinst_path $abs_ladir"
+         fi
+       fi # $installed = yes
+       name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+       # This library was specified with -dlpreopen.
+       if test "$pass" = dlpreopen; then
+         if test -z "$libdir"; then
+           $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+           exit $EXIT_FAILURE
+         fi
+         # Prefer using a static library (so that no silly _DYNAMIC symbols
+         # are required to link).
+         if test -n "$old_library"; then
+           newdlprefiles="$newdlprefiles $dir/$old_library"
+         # Otherwise, use the dlname, so that lt_dlopen finds it.
+         elif test -n "$dlname"; then
+           newdlprefiles="$newdlprefiles $dir/$dlname"
+         else
+           newdlprefiles="$newdlprefiles $dir/$linklib"
+         fi
+       fi # $pass = dlpreopen
+
+       if test -z "$libdir"; then
+         # Link the convenience library
+         if test "$linkmode" = lib; then
+           deplibs="$dir/$old_library $deplibs"
+         elif test "$linkmode,$pass" = "prog,link"; then
+           compile_deplibs="$dir/$old_library $compile_deplibs"
+           finalize_deplibs="$dir/$old_library $finalize_deplibs"
+         else
+           deplibs="$lib $deplibs" # used for prog,scan pass
+         fi
+         continue
+       fi
+
+
+       if test "$linkmode" = prog && test "$pass" != link; then
+         newlib_search_path="$newlib_search_path $ladir"
+         deplibs="$lib $deplibs"
+
+         linkalldeplibs=no
+         if test "$link_all_deplibs" != no || test -z "$library_names" ||
+            test "$build_libtool_libs" = no; then
+           linkalldeplibs=yes
+         fi
+
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           case $deplib in
+           -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+           esac
+           # Need to link against all dependency_libs?
+           if test "$linkalldeplibs" = yes; then
+             deplibs="$deplib $deplibs"
+           else
+             # Need to hardcode shared library paths
+             # or/and link against static libraries
+             newdependency_libs="$deplib $newdependency_libs"
+           fi
+           if test "X$duplicate_deps" = "Xyes" ; then
+             case "$tmp_libs " in
+             *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+             esac
+           fi
+           tmp_libs="$tmp_libs $deplib"
+         done # for deplib
+         continue
+       fi # $linkmode = prog...
+
+       if test "$linkmode,$pass" = "prog,link"; then
+         if test -n "$library_names" &&
+            { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+           # We need to hardcode the library path
+           if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+             # Make sure the rpath contains only unique directories.
+             case "$temp_rpath " in
+             *" $dir "*) ;;
+             *" $absdir "*) ;;
+             *) temp_rpath="$temp_rpath $dir" ;;
+             esac
+           fi
+
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) compile_rpath="$compile_rpath $absdir"
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) finalize_rpath="$finalize_rpath $libdir"
+             esac
+             ;;
+           esac
+         fi # $linkmode,$pass = prog,link...
+
+         if test "$alldeplibs" = yes &&
+            { test "$deplibs_check_method" = pass_all ||
+              { test "$build_libtool_libs" = yes &&
+                test -n "$library_names"; }; }; then
+           # We only need to search for static libraries
+           continue
+         fi
+       fi
+
+       link_static=no # Whether the deplib will be linked statically
+       if test -n "$library_names" &&
+          { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+         if test "$installed" = no; then
+           notinst_deplibs="$notinst_deplibs $lib"
+           need_relink=yes
+         fi
+         # This is a shared library
+
+         # Warn about portability, can't link against -module's on
+         # some systems (darwin)
+         if test "$shouldnotlink" = yes && test "$pass" = link ; then
+           $echo
+           if test "$linkmode" = prog; then
+             $echo "*** Warning: Linking the executable $output against the loadable module"
+           else
+             $echo "*** Warning: Linking the shared library $output against the loadable module"
+           fi
+           $echo "*** $linklib is not portable!"
+         fi
+         if test "$linkmode" = lib &&
+            test "$hardcode_into_libs" = yes; then
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) compile_rpath="$compile_rpath $absdir"
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) finalize_rpath="$finalize_rpath $libdir"
+             esac
+             ;;
+           esac
+         fi
+
+         if test -n "$old_archive_from_expsyms_cmds"; then
+           # figure out the soname
+           set dummy $library_names
+           realname="$2"
+           shift; shift
+           libname=`eval \\$echo \"$libname_spec\"`
+           # use dlname if we got it. it's perfectly good, no?
+           if test -n "$dlname"; then
+             soname="$dlname"
+           elif test -n "$soname_spec"; then
+             # bleh windows
+             case $host in
+             *cygwin* | mingw*)
+               major=`expr $current - $age`
+               versuffix="-$major"
+               ;;
+             esac
+             eval soname=\"$soname_spec\"
+           else
+             soname="$realname"
+           fi
+
+           # Make a new name for the extract_expsyms_cmds to use
+           soroot="$soname"
+           soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+           newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+           # If the library has no export list, then create one now
+           if test -f "$output_objdir/$soname-def"; then :
+           else
+             $show "extracting exported symbol list from \`$soname'"
+             save_ifs="$IFS"; IFS='~'
+             cmds=$extract_expsyms_cmds
+             for cmd in $cmds; do
+               IFS="$save_ifs"
+               eval cmd=\"$cmd\"
+               $show "$cmd"
+               $run eval "$cmd" || exit $?
+             done
+             IFS="$save_ifs"
+           fi
+
+           # Create $newlib
+           if test -f "$output_objdir/$newlib"; then :; else
+             $show "generating import library for \`$soname'"
+             save_ifs="$IFS"; IFS='~'
+             cmds=$old_archive_from_expsyms_cmds
+             for cmd in $cmds; do
+               IFS="$save_ifs"
+               eval cmd=\"$cmd\"
+               $show "$cmd"
+               $run eval "$cmd" || exit $?
+             done
+             IFS="$save_ifs"
+           fi
+           # make sure the library variables are pointing to the new library
+           dir=$output_objdir
+           linklib=$newlib
+         fi # test -n "$old_archive_from_expsyms_cmds"
+
+         if test "$linkmode" = prog || test "$mode" != relink; then
+           add_shlibpath=
+           add_dir=
+           add=
+           lib_linked=yes
+           case $hardcode_action in
+           immediate | unsupported)
+             if test "$hardcode_direct" = no; then
+               add="$dir/$linklib"
+               case $host in
+                 *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+                 *-*-darwin* )
+                   # if the lib is a module then we can not link against
+                   # it, someone is ignoring the new warnings I added
+                   if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then
+                     $echo "** Warning, lib $linklib is a module, not a shared library"
+                     if test -z "$old_library" ; then
+                       $echo
+                       $echo "** And there doesn't seem to be a static archive available"
+                       $echo "** The link will probably fail, sorry"
+                     else
+                       add="$dir/$old_library"
+                     fi
+                   fi
+               esac
+             elif test "$hardcode_minus_L" = no; then
+               case $host in
+               *-*-sunos*) add_shlibpath="$dir" ;;
+               esac
+               add_dir="-L$dir"
+               add="-l$name"
+             elif test "$hardcode_shlibpath_var" = no; then
+               add_shlibpath="$dir"
+               add="-l$name"
+             else
+               lib_linked=no
+             fi
+             ;;
+           relink)
+             if test "$hardcode_direct" = yes; then
+               add="$dir/$linklib"
+             elif test "$hardcode_minus_L" = yes; then
+               add_dir="-L$dir"
+               # Try looking first in the location we're being installed to.
+               if test -n "$inst_prefix_dir"; then
+                 case "$libdir" in
+                   [\\/]*)
+                     add_dir="$add_dir -L$inst_prefix_dir$libdir"
+                     ;;
+                 esac
+               fi
+               add="-l$name"
+             elif test "$hardcode_shlibpath_var" = yes; then
+               add_shlibpath="$dir"
+               add="-l$name"
+             else
+               lib_linked=no
+             fi
+             ;;
+           *) lib_linked=no ;;
+           esac
+
+           if test "$lib_linked" != yes; then
+             $echo "$modename: configuration error: unsupported hardcode properties"
+             exit $EXIT_FAILURE
+           fi
+
+           if test -n "$add_shlibpath"; then
+             case :$compile_shlibpath: in
+             *":$add_shlibpath:"*) ;;
+             *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+             esac
+           fi
+           if test "$linkmode" = prog; then
+             test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+             test -n "$add" && compile_deplibs="$add $compile_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+             if test "$hardcode_direct" != yes && \
+                test "$hardcode_minus_L" != yes && \
+                test "$hardcode_shlibpath_var" = yes; then
+               case :$finalize_shlibpath: in
+               *":$libdir:"*) ;;
+               *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+               esac
+             fi
+           fi
+         fi
+
+         if test "$linkmode" = prog || test "$mode" = relink; then
+           add_shlibpath=
+           add_dir=
+           add=
+           # Finalize command for both is simple: just hardcode it.
+           if test "$hardcode_direct" = yes; then
+             add="$libdir/$linklib"
+           elif test "$hardcode_minus_L" = yes; then
+             add_dir="-L$libdir"
+             add="-l$name"
+           elif test "$hardcode_shlibpath_var" = yes; then
+             case :$finalize_shlibpath: in
+             *":$libdir:"*) ;;
+             *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+             esac
+             add="-l$name"
+           elif test "$hardcode_automatic" = yes; then
+             if test -n "$inst_prefix_dir" &&
+                test -f "$inst_prefix_dir$libdir/$linklib" ; then
+               add="$inst_prefix_dir$libdir/$linklib"
+             else
+               add="$libdir/$linklib"
+             fi
+           else
+             # We cannot seem to hardcode it, guess we'll fake it.
+             add_dir="-L$libdir"
+             # Try looking first in the location we're being installed to.
+             if test -n "$inst_prefix_dir"; then
+               case "$libdir" in
+                 [\\/]*)
+                   add_dir="$add_dir -L$inst_prefix_dir$libdir"
+                   ;;
+               esac
+             fi
+             add="-l$name"
+           fi
+
+           if test "$linkmode" = prog; then
+             test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+             test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+           fi
+         fi
+       elif test "$linkmode" = prog; then
+         # Here we assume that one of hardcode_direct or hardcode_minus_L
+         # is not unsupported.  This is valid on all known static and
+         # shared platforms.
+         if test "$hardcode_direct" != unsupported; then
+           test -n "$old_library" && linklib="$old_library"
+           compile_deplibs="$dir/$linklib $compile_deplibs"
+           finalize_deplibs="$dir/$linklib $finalize_deplibs"
+         else
+           compile_deplibs="-l$name -L$dir $compile_deplibs"
+           finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+         fi
+       elif test "$build_libtool_libs" = yes; then
+         # Not a shared library
+         if test "$deplibs_check_method" != pass_all; then
+           # We're trying link a shared library against a static one
+           # but the system doesn't support it.
+
+           # Just print a warning and add the library to dependency_libs so
+           # that the program can be linked against the static library.
+           $echo
+           $echo "*** Warning: This system can not link to static lib archive $lib."
+           $echo "*** I have the capability to make that library automatically link in when"
+           $echo "*** you link to this library.  But I can only do this if you have a"
+           $echo "*** shared version of the library, which you do not appear to have."
+           if test "$module" = yes; then
+             $echo "*** But as you try to build a module library, libtool will still create "
+             $echo "*** a static module, that should work as long as the dlopening application"
+             $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+             if test -z "$global_symbol_pipe"; then
+               $echo
+               $echo "*** However, this would only work if libtool was able to extract symbol"
+               $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+               $echo "*** not find such a program.  So, this module is probably useless."
+               $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+             fi
+             if test "$build_old_libs" = no; then
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         else
+           convenience="$convenience $dir/$old_library"
+           old_convenience="$old_convenience $dir/$old_library"
+           deplibs="$dir/$old_library $deplibs"
+           link_static=yes
+         fi
+       fi # link shared/static library?
+
+       if test "$linkmode" = lib; then
+         if test -n "$dependency_libs" &&
+            { test "$hardcode_into_libs" != yes ||
+              test "$build_old_libs" = yes ||
+              test "$link_static" = yes; }; then
+           # Extract -R from dependency_libs
+           temp_deplibs=
+           for libdir in $dependency_libs; do
+             case $libdir in
+             -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+                  case " $xrpath " in
+                  *" $temp_xrpath "*) ;;
+                  *) xrpath="$xrpath $temp_xrpath";;
+                  esac;;
+             *) temp_deplibs="$temp_deplibs $libdir";;
+             esac
+           done
+           dependency_libs="$temp_deplibs"
+         fi
+
+         newlib_search_path="$newlib_search_path $absdir"
+         # Link against this library
+         test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+         # ... and its dependency_libs
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           newdependency_libs="$deplib $newdependency_libs"
+           if test "X$duplicate_deps" = "Xyes" ; then
+             case "$tmp_libs " in
+             *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+             esac
+           fi
+           tmp_libs="$tmp_libs $deplib"
+         done
+
+         if test "$link_all_deplibs" != no; then
+           # Add the search paths of all dependency libraries
+           for deplib in $dependency_libs; do
+             case $deplib in
+             -L*) path="$deplib" ;;
+             *.la)
+               dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+               test "X$dir" = "X$deplib" && dir="."
+               # We need an absolute path.
+               case $dir in
+               [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+               *)
+                 absdir=`cd "$dir" && pwd`
+                 if test -z "$absdir"; then
+                   $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+                   absdir="$dir"
+                 fi
+                 ;;
+               esac
+               if grep "^installed=no" $deplib > /dev/null; then
+                 path="$absdir/$objdir"
+               else
+                 eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+                 if test -z "$libdir"; then
+                   $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+                   exit $EXIT_FAILURE
+                 fi
+                 if test "$absdir" != "$libdir"; then
+                   $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+                 fi
+                 path="$absdir"
+               fi
+               depdepl=
+               case $host in
+               *-*-darwin*)
+                 # we do not want to link against static libs,
+                 # but need to link against shared
+                 eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+                 if test -n "$deplibrary_names" ; then
+                   for tmp in $deplibrary_names ; do
+                     depdepl=$tmp
+                   done
+                   if test -f "$path/$depdepl" ; then
+                     depdepl="$path/$depdepl"
+                   fi
+                   # do not add paths which are already there
+                   case " $newlib_search_path " in
+                   *" $path "*) ;;
+                   *) newlib_search_path="$newlib_search_path $path";;
+                   esac
+                 fi
+                 path=""
+                 ;;
+               *)
+                 path="-L$path"
+                 ;;
+               esac
+               ;;
+             -l*)
+               case $host in
+               *-*-darwin*)
+                 # Again, we only want to link against shared libraries
+                 eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+                 for tmp in $newlib_search_path ; do
+                   if test -f "$tmp/lib$tmp_libs.dylib" ; then
+                     eval depdepl="$tmp/lib$tmp_libs.dylib"
+                     break
+                   fi
+                 done
+                 path=""
+                 ;;
+               *) continue ;;
+               esac
+               ;;
+             *) continue ;;
+             esac
+             case " $deplibs " in
+             *" $path "*) ;;
+             *) deplibs="$path $deplibs" ;;
+             esac
+             case " $deplibs " in
+             *" $depdepl "*) ;;
+             *) deplibs="$depdepl $deplibs" ;;
+             esac
+           done
+         fi # link_all_deplibs != no
+       fi # linkmode = lib
+      done # for deplib in $libs
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+       # Link the dlpreopened libraries before other libraries
+       for deplib in $save_deplibs; do
+         deplibs="$deplib $deplibs"
+       done
+      fi
+      if test "$pass" != dlopen; then
+       if test "$pass" != conv; then
+         # Make sure lib_search_path contains only unique directories.
+         lib_search_path=
+         for dir in $newlib_search_path; do
+           case "$lib_search_path " in
+           *" $dir "*) ;;
+           *) lib_search_path="$lib_search_path $dir" ;;
+           esac
+         done
+         newlib_search_path=
+       fi
+
+       if test "$linkmode,$pass" != "prog,link"; then
+         vars="deplibs"
+       else
+         vars="compile_deplibs finalize_deplibs"
+       fi
+       for var in $vars dependency_libs; do
+         # Add libraries to $var in reverse order
+         eval tmp_libs=\"\$$var\"
+         new_libs=
+         for deplib in $tmp_libs; do
+           # FIXME: Pedantically, this is the right thing to do, so
+           #        that some nasty dependency loop isn't accidentally
+           #        broken:
+           #new_libs="$deplib $new_libs"
+           # Pragmatically, this seems to cause very few problems in
+           # practice:
+           case $deplib in
+           -L*) new_libs="$deplib $new_libs" ;;
+           -R*) ;;
+           *)
+             # And here is the reason: when a library appears more
+             # than once as an explicit dependence of a library, or
+             # is implicitly linked in more than once by the
+             # compiler, it is considered special, and multiple
+             # occurrences thereof are not removed.  Compare this
+             # with having the same library being listed as a
+             # dependency of multiple other libraries: in this case,
+             # we know (pedantically, we assume) the library does not
+             # need to be listed more than once, so we keep only the
+             # last copy.  This is not always right, but it is rare
+             # enough that we require users that really mean to play
+             # such unportable linking tricks to link the library
+             # using -Wl,-lname, so that libtool does not consider it
+             # for duplicate removal.
+             case " $specialdeplibs " in
+             *" $deplib "*) new_libs="$deplib $new_libs" ;;
+             *)
+               case " $new_libs " in
+               *" $deplib "*) ;;
+               *) new_libs="$deplib $new_libs" ;;
+               esac
+               ;;
+             esac
+             ;;
+           esac
+         done
+         tmp_libs=
+         for deplib in $new_libs; do
+           case $deplib in
+           -L*)
+             case " $tmp_libs " in
+             *" $deplib "*) ;;
+             *) tmp_libs="$tmp_libs $deplib" ;;
+             esac
+             ;;
+           *) tmp_libs="$tmp_libs $deplib" ;;
+           esac
+         done
+         eval $var=\"$tmp_libs\"
+       done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+       case " $predeps $postdeps $compiler_lib_search_path " in
+       *" $i "*)
+         i=""
+         ;;
+       esac
+       if test -n "$i" ; then
+         tmp_libs="$tmp_libs $i"
+       fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$deplibs"; then
+       $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+       $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+       $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+       $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+      fi
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      objs="$objs$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+       name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+       eval shared_ext=\"$shrext_cmds\"
+       eval libname=\"$libname_spec\"
+       ;;
+      *)
+       if test "$module" = no; then
+         $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+       fi
+       if test "$need_lib_prefix" != no; then
+         # Add the "lib" prefix for modules if required
+         name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+         eval shared_ext=\"$shrext_cmds\"
+         eval libname=\"$libname_spec\"
+       else
+         libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+       fi
+       ;;
+      esac
+
+      if test -n "$objs"; then
+       if test "$deplibs_check_method" != pass_all; then
+         $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+         exit $EXIT_FAILURE
+       else
+         $echo
+         $echo "*** Warning: Linking the shared library $output against the non-libtool"
+         $echo "*** objects $objs is not portable!"
+         libobjs="$libobjs $objs"
+       fi
+      fi
+
+      if test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+      fi
+
+      set dummy $rpath
+      if test "$#" -gt 2; then
+       $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+      fi
+      install_libdir="$2"
+
+      oldlibs=
+      if test -z "$rpath"; then
+       if test "$build_libtool_libs" = yes; then
+         # Building a libtool convenience library.
+         # Some compilers have problems with a `.al' extension so
+         # convenience libraries should have the same extension an
+         # archive normally would.
+         oldlibs="$output_objdir/$libname.$libext $oldlibs"
+         build_libtool_libs=convenience
+         build_old_libs=yes
+       fi
+
+       if test -n "$vinfo"; then
+         $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+       fi
+
+       if test -n "$release"; then
+         $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+       fi
+      else
+
+       # Parse the version information argument.
+       save_ifs="$IFS"; IFS=':'
+       set dummy $vinfo 0 0 0
+       IFS="$save_ifs"
+
+       if test -n "$8"; then
+         $echo "$modename: too many parameters to \`-version-info'" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       # convert absolute version numbers to libtool ages
+       # this retains compatibility with .la files and attempts
+       # to make the code below a bit more comprehensible
+
+       case $vinfo_number in
+       yes)
+         number_major="$2"
+         number_minor="$3"
+         number_revision="$4"
+         #
+         # There are really only two kinds -- those that
+         # use the current revision as the major version
+         # and those that subtract age and use age as
+         # a minor version.  But, then there is irix
+         # which has an extra 1 added just for fun
+         #
+         case $version_type in
+         darwin|linux|osf|windows)
+           current=`expr $number_major + $number_minor`
+           age="$number_minor"
+           revision="$number_revision"
+           ;;
+         freebsd-aout|freebsd-elf|sunos)
+           current="$number_major"
+           revision="$number_minor"
+           age="0"
+           ;;
+         irix|nonstopux)
+           current=`expr $number_major + $number_minor - 1`
+           age="$number_minor"
+           revision="$number_minor"
+           ;;
+         esac
+         ;;
+       no)
+         current="$2"
+         revision="$3"
+         age="$4"
+         ;;
+       esac
+
+       # Check that each of the things are valid numbers.
+       case $current in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+
+       case $revision in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+
+       case $age in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+
+       if test "$age" -gt "$current"; then
+         $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       # Calculate the version variables.
+       major=
+       versuffix=
+       verstring=
+       case $version_type in
+       none) ;;
+
+       darwin)
+         # Like Linux, but with the current version available in
+         # verstring for coding it into the library header
+         major=.`expr $current - $age`
+         versuffix="$major.$age.$revision"
+         # Darwin ld doesn't like 0 for these options...
+         minor_current=`expr $current + 1`
+         verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+         ;;
+
+       freebsd-aout)
+         major=".$current"
+         versuffix=".$current.$revision";
+         ;;
+
+       freebsd-elf)
+         major=".$current"
+         versuffix=".$current";
+         ;;
+
+       irix | nonstopux)
+         major=`expr $current - $age + 1`
+
+         case $version_type in
+           nonstopux) verstring_prefix=nonstopux ;;
+           *)         verstring_prefix=sgi ;;
+         esac
+         verstring="$verstring_prefix$major.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$revision
+         while test "$loop" -ne 0; do
+           iface=`expr $revision - $loop`
+           loop=`expr $loop - 1`
+           verstring="$verstring_prefix$major.$iface:$verstring"
+         done
+
+         # Before this point, $major must not contain `.'.
+         major=.$major
+         versuffix="$major.$revision"
+         ;;
+
+       linux)
+         major=.`expr $current - $age`
+         versuffix="$major.$age.$revision"
+         ;;
+
+       osf)
+         major=.`expr $current - $age`
+         versuffix=".$current.$age.$revision"
+         verstring="$current.$age.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$age
+         while test "$loop" -ne 0; do
+           iface=`expr $current - $loop`
+           loop=`expr $loop - 1`
+           verstring="$verstring:${iface}.0"
+         done
+
+         # Make executables depend on our current version.
+         verstring="$verstring:${current}.0"
+         ;;
+
+       sunos)
+         major=".$current"
+         versuffix=".$current.$revision"
+         ;;
+
+       windows)
+         # Use '-' rather than '.', since we only want one
+         # extension on DOS 8.3 filesystems.
+         major=`expr $current - $age`
+         versuffix="-$major"
+         ;;
+
+       *)
+         $echo "$modename: unknown library version type \`$version_type'" 1>&2
+         $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+
+       # Clear the version info if we defaulted, and they specified a release.
+       if test -z "$vinfo" && test -n "$release"; then
+         major=
+         case $version_type in
+         darwin)
+           # we can't check for "0.0" in archive_cmds due to quoting
+           # problems, so we reset it completely
+           verstring=
+           ;;
+         *)
+           verstring="0.0"
+           ;;
+         esac
+         if test "$need_version" = no; then
+           versuffix=
+         else
+           versuffix=".0.0"
+         fi
+       fi
+
+       # Remove version info from name if versioning should be avoided
+       if test "$avoid_version" = yes && test "$need_version" = no; then
+         major=
+         versuffix=
+         verstring=""
+       fi
+
+       # Check to see if the archive will have undefined symbols.
+       if test "$allow_undefined" = yes; then
+         if test "$allow_undefined_flag" = unsupported; then
+           $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+           build_libtool_libs=no
+           build_old_libs=yes
+         fi
+       else
+         # Don't allow undefined symbols.
+         allow_undefined_flag="$no_undefined_flag"
+       fi
+      fi
+
+      if test "$mode" != relink; then
+       # Remove our outputs, but don't remove object files since they
+       # may have been created when compiling PIC objects.
+       removelist=
+       tempremovelist=`$echo "$output_objdir/*"`
+       for p in $tempremovelist; do
+         case $p in
+           *.$objext)
+              ;;
+           $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+              if test "X$precious_files_regex" != "X"; then
+                if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+                then
+                  continue
+                fi
+              fi
+              removelist="$removelist $p"
+              ;;
+           *) ;;
+         esac
+       done
+       if test -n "$removelist"; then
+         $show "${rm}r $removelist"
+         $run ${rm}r $removelist
+       fi
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+       oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+       # Transform .lo files to .o files.
+       oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      for path in $notinst_path; do
+       lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
+       deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
+       dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+      done
+
+      if test -n "$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       temp_xrpath=
+       for libdir in $xrpath; do
+         temp_xrpath="$temp_xrpath -R$libdir"
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) finalize_rpath="$finalize_rpath $libdir" ;;
+         esac
+       done
+       if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+         dependency_libs="$temp_xrpath $dependency_libs"
+       fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+       case " $dlprefiles $dlfiles " in
+       *" $lib "*) ;;
+       *) dlfiles="$dlfiles $lib" ;;
+       esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+       case "$dlprefiles " in
+       *" $lib "*) ;;
+       *) dlprefiles="$dlprefiles $lib" ;;
+       esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+       if test -n "$rpath"; then
+         case $host in
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+           # these systems don't actually have a c library (as such)!
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C library is in the System framework
+           deplibs="$deplibs -framework System"
+           ;;
+         *-*-netbsd*)
+           # Don't link with libc until the a.out ld.so is fixed.
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+           # Do not include libc due to us having libc/libc_r.
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *)
+           # Add libc to deplibs on all other systems if necessary.
+           if test "$build_libtool_need_lc" = "yes"; then
+             deplibs="$deplibs -lc"
+           fi
+           ;;
+         esac
+       fi
+
+       # Transform deplibs into only deplibs that can be linked in shared.
+       name_save=$name
+       libname_save=$libname
+       release_save=$release
+       versuffix_save=$versuffix
+       major_save=$major
+       # I'm not sure if I'm treating the release correctly.  I think
+       # release should show up in the -l (ie -lgmp5) so we don't want to
+       # add it in twice.  Is that correct?
+       release=""
+       versuffix=""
+       major=""
+       newdeplibs=
+       droppeddeps=no
+       case $deplibs_check_method in
+       pass_all)
+         # Don't check for shared/static.  Everything works.
+         # This might be a little naive.  We might want to check
+         # whether the library exists or not.  But this is on
+         # osf3 & osf4 and I'm not really sure... Just
+         # implementing what was already the behavior.
+         newdeplibs=$deplibs
+         ;;
+       test_compile)
+         # This code stresses the "libraries are programs" paradigm to its
+         # limits. Maybe even breaks it.  We compile a program, linking it
+         # against the deplibs as a proxy for the library.  Then we can check
+         # whether they linked in statically or dynamically with ldd.
+         $rm conftest.c
+         cat > conftest.c <<EOF
+         int main() { return 0; }
+EOF
+         $rm conftest
+         $LTCC -o conftest conftest.c $deplibs
+         if test "$?" -eq 0 ; then
+           ldd_output=`ldd conftest`
+           for i in $deplibs; do
+             name="`expr $i : '-l\(.*\)'`"
+             # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" -ne "0"; then
+               if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                 case " $predeps $postdeps " in
+                 *" $i "*)
+                   newdeplibs="$newdeplibs $i"
+                   i=""
+                   ;;
+                 esac
+               fi
+               if test -n "$i" ; then
+                 libname=`eval \\$echo \"$libname_spec\"`
+                 deplib_matches=`eval \\$echo \"$library_names_spec\"`
+                 set dummy $deplib_matches
+                 deplib_match=$2
+                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                   newdeplibs="$newdeplibs $i"
+                 else
+                   droppeddeps=yes
+                   $echo
+                   $echo "*** Warning: dynamic linker does not accept needed library $i."
+                   $echo "*** I have the capability to make that library automatically link in when"
+                   $echo "*** you link to this library.  But I can only do this if you have a"
+                   $echo "*** shared version of the library, which I believe you do not have"
+                   $echo "*** because a test_compile did reveal that the linker did not use it for"
+                   $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+                 fi
+               fi
+             else
+               newdeplibs="$newdeplibs $i"
+             fi
+           done
+         else
+           # Error occurred in the first compile.  Let's try to salvage
+           # the situation: Compile a separate program for each library.
+           for i in $deplibs; do
+             name="`expr $i : '-l\(.*\)'`"
+             # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" != "0"; then
+               $rm conftest
+               $LTCC -o conftest conftest.c $i
+               # Did it work?
+               if test "$?" -eq 0 ; then
+                 ldd_output=`ldd conftest`
+                 if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                   case " $predeps $postdeps " in
+                   *" $i "*)
+                     newdeplibs="$newdeplibs $i"
+                     i=""
+                     ;;
+                   esac
+                 fi
+                 if test -n "$i" ; then
+                   libname=`eval \\$echo \"$libname_spec\"`
+                   deplib_matches=`eval \\$echo \"$library_names_spec\"`
+                   set dummy $deplib_matches
+                   deplib_match=$2
+                   if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                     newdeplibs="$newdeplibs $i"
+                   else
+                     droppeddeps=yes
+                     $echo
+                     $echo "*** Warning: dynamic linker does not accept needed library $i."
+                     $echo "*** I have the capability to make that library automatically link in when"
+                     $echo "*** you link to this library.  But I can only do this if you have a"
+                     $echo "*** shared version of the library, which you do not appear to have"
+                     $echo "*** because a test_compile did reveal that the linker did not use this one"
+                     $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+                   fi
+                 fi
+               else
+                 droppeddeps=yes
+                 $echo
+                 $echo "*** Warning!  Library $i is needed by this library but I was not able to"
+                 $echo "***  make it link in!  You will probably need to install it or some"
+                 $echo "*** library that it depends on before this library will be fully"
+                 $echo "*** functional.  Installing it before continuing would be even better."
+               fi
+             else
+               newdeplibs="$newdeplibs $i"
+             fi
+           done
+         fi
+         ;;
+       file_magic*)
+         set dummy $deplibs_check_method
+         file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+         for a_deplib in $deplibs; do
+           name="`expr $a_deplib : '-l\(.*\)'`"
+           # If $name is empty we are operating on a -L argument.
+            if test "$name" != "" && test  "$name" != "0"; then
+             if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 newdeplibs="$newdeplibs $a_deplib"
+                 a_deplib=""
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib" ; then
+               libname=`eval \\$echo \"$libname_spec\"`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+                 for potent_lib in $potential_libs; do
+                     # Follow soft links.
+                     if ls -lLd "$potent_lib" 2>/dev/null \
+                        | grep " -> " >/dev/null; then
+                       continue
+                     fi
+                     # The statement above tries to avoid entering an
+                     # endless loop below, in case of cyclic links.
+                     # We might still enter an endless loop, since a link
+                     # loop can be closed while we follow links,
+                     # but so what?
+                     potlib="$potent_lib"
+                     while test -h "$potlib" 2>/dev/null; do
+                       potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+                       case $potliblink in
+                       [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+                       *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+                       esac
+                     done
+                     if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+                        | ${SED} 10q \
+                        | $EGREP "$file_magic_regex" > /dev/null; then
+                       newdeplibs="$newdeplibs $a_deplib"
+                       a_deplib=""
+                       break 2
+                     fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib" ; then
+               droppeddeps=yes
+               $echo
+               $echo "*** Warning: linker path does not have real file for library $a_deplib."
+               $echo "*** I have the capability to make that library automatically link in when"
+               $echo "*** you link to this library.  But I can only do this if you have a"
+               $echo "*** shared version of the library, which you do not appear to have"
+               $echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib" ; then
+                 $echo "*** with $libname but no candidates were found. (...for file magic test)"
+               else
+                 $echo "*** with $libname and none of the candidates passed a file format test"
+                 $echo "*** using a file magic. Last file checked: $potlib"
+               fi
+             fi
+           else
+             # Add a -L argument.
+             newdeplibs="$newdeplibs $a_deplib"
+           fi
+         done # Gone through all deplibs.
+         ;;
+       match_pattern*)
+         set dummy $deplibs_check_method
+         match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+         for a_deplib in $deplibs; do
+           name="`expr $a_deplib : '-l\(.*\)'`"
+           # If $name is empty we are operating on a -L argument.
+           if test -n "$name" && test "$name" != "0"; then
+             if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 newdeplibs="$newdeplibs $a_deplib"
+                 a_deplib=""
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib" ; then
+               libname=`eval \\$echo \"$libname_spec\"`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+                 for potent_lib in $potential_libs; do
+                   potlib="$potent_lib" # see symlink-check above in file_magic test
+                   if eval $echo \"$potent_lib\" 2>/dev/null \
+                       | ${SED} 10q \
+                       | $EGREP "$match_pattern_regex" > /dev/null; then
+                     newdeplibs="$newdeplibs $a_deplib"
+                     a_deplib=""
+                     break 2
+                   fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib" ; then
+               droppeddeps=yes
+               $echo
+               $echo "*** Warning: linker path does not have real file for library $a_deplib."
+               $echo "*** I have the capability to make that library automatically link in when"
+               $echo "*** you link to this library.  But I can only do this if you have a"
+               $echo "*** shared version of the library, which you do not appear to have"
+               $echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib" ; then
+                 $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+               else
+                 $echo "*** with $libname and none of the candidates passed a file format test"
+                 $echo "*** using a regex pattern. Last file checked: $potlib"
+               fi
+             fi
+           else
+             # Add a -L argument.
+             newdeplibs="$newdeplibs $a_deplib"
+           fi
+         done # Gone through all deplibs.
+         ;;
+       none | unknown | *)
+         newdeplibs=""
+         tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+           -e 's/ -[LR][^ ]*//g'`
+         if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+           for i in $predeps $postdeps ; do
+             # can't use Xsed below, because $i might contain '/'
+             tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+           done
+         fi
+         if $echo "X $tmp_deplibs" | $Xsed -e 's/[     ]//g' \
+           | grep . >/dev/null; then
+           $echo
+           if test "X$deplibs_check_method" = "Xnone"; then
+             $echo "*** Warning: inter-library dependencies are not supported in this platform."
+           else
+             $echo "*** Warning: inter-library dependencies are not known to be supported."
+           fi
+           $echo "*** All declared inter-library dependencies are being dropped."
+           droppeddeps=yes
+         fi
+         ;;
+       esac
+       versuffix=$versuffix_save
+       major=$major_save
+       release=$release_save
+       libname=$libname_save
+       name=$name_save
+
+       case $host in
+       *-*-rhapsody* | *-*-darwin1.[012])
+         # On Rhapsody replace the C library is the System framework
+         newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+         ;;
+       esac
+
+       if test "$droppeddeps" = yes; then
+         if test "$module" = yes; then
+           $echo
+           $echo "*** Warning: libtool could not satisfy all declared inter-library"
+           $echo "*** dependencies of module $libname.  Therefore, libtool will create"
+           $echo "*** a static module, that should work as long as the dlopening"
+           $echo "*** application is linked with the -dlopen flag."
+           if test -z "$global_symbol_pipe"; then
+             $echo
+             $echo "*** However, this would only work if libtool was able to extract symbol"
+             $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+             $echo "*** not find such a program.  So, this module is probably useless."
+             $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+           fi
+           if test "$build_old_libs" = no; then
+             oldlibs="$output_objdir/$libname.$libext"
+             build_libtool_libs=module
+             build_old_libs=yes
+           else
+             build_libtool_libs=no
+           fi
+         else
+           $echo "*** The inter-library dependencies that have been dropped here will be"
+           $echo "*** automatically added whenever a program is linked with this library"
+           $echo "*** or is declared to -dlopen it."
+
+           if test "$allow_undefined" = no; then
+             $echo
+             $echo "*** Since this library must not contain undefined symbols,"
+             $echo "*** because either the platform does not support them or"
+             $echo "*** it was explicitly requested with -no-undefined,"
+             $echo "*** libtool will only create a static version of it."
+             if test "$build_old_libs" = no; then
+               oldlibs="$output_objdir/$libname.$libext"
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         fi
+       fi
+       # Done checking deplibs!
+       deplibs=$newdeplibs
+      fi
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+       if test "$hardcode_into_libs" = yes; then
+         # Hardcode the library paths
+         hardcode_libdirs=
+         dep_rpath=
+         rpath="$finalize_rpath"
+         test "$mode" != relink && rpath="$compile_rpath$rpath"
+         for libdir in $rpath; do
+           if test -n "$hardcode_libdir_flag_spec"; then
+             if test -n "$hardcode_libdir_separator"; then
+               if test -z "$hardcode_libdirs"; then
+                 hardcode_libdirs="$libdir"
+               else
+                 # Just accumulate the unique libdirs.
+                 case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+                 *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+                   ;;
+                 *)
+                   hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+                   ;;
+                 esac
+               fi
+             else
+               eval flag=\"$hardcode_libdir_flag_spec\"
+               dep_rpath="$dep_rpath $flag"
+             fi
+           elif test -n "$runpath_var"; then
+             case "$perm_rpath " in
+             *" $libdir "*) ;;
+             *) perm_rpath="$perm_rpath $libdir" ;;
+             esac
+           fi
+         done
+         # Substitute the hardcoded libdirs into the rpath.
+         if test -n "$hardcode_libdir_separator" &&
+            test -n "$hardcode_libdirs"; then
+           libdir="$hardcode_libdirs"
+           if test -n "$hardcode_libdir_flag_spec_ld"; then
+             eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+           else
+             eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+           fi
+         fi
+         if test -n "$runpath_var" && test -n "$perm_rpath"; then
+           # We should set the runpath_var.
+           rpath=
+           for dir in $perm_rpath; do
+             rpath="$rpath$dir:"
+           done
+           eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+         fi
+         test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+       fi
+
+       shlibpath="$finalize_shlibpath"
+       test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+       if test -n "$shlibpath"; then
+         eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+       fi
+
+       # Get the real and link names of the library.
+       eval shared_ext=\"$shrext_cmds\"
+       eval library_names=\"$library_names_spec\"
+       set dummy $library_names
+       realname="$2"
+       shift; shift
+
+       if test -n "$soname_spec"; then
+         eval soname=\"$soname_spec\"
+       else
+         soname="$realname"
+       fi
+       if test -z "$dlname"; then
+         dlname=$soname
+       fi
+
+       lib="$output_objdir/$realname"
+       for link
+       do
+         linknames="$linknames $link"
+       done
+
+       # Use standard objects if they are pic
+       test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+       # Prepare the list of exported symbols
+       if test -z "$export_symbols"; then
+         if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+           $show "generating symbol list for \`$libname.la'"
+           export_symbols="$output_objdir/$libname.exp"
+           $run $rm $export_symbols
+           cmds=$export_symbols_cmds
+           save_ifs="$IFS"; IFS='~'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             eval cmd=\"$cmd\"
+             if len=`expr "X$cmd" : ".*"` &&
+              test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+               $show "$cmd"
+               $run eval "$cmd" || exit $?
+               skipped_export=false
+             else
+               # The command line is too long to execute in one step.
+               $show "using reloadable object file for export list..."
+               skipped_export=:
+             fi
+           done
+           IFS="$save_ifs"
+           if test -n "$export_symbols_regex"; then
+             $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+             $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+             $run eval '$mv "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+       fi
+
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+       fi
+
+       tmp_deplibs=
+       for test_deplib in $deplibs; do
+               case " $convenience " in
+               *" $test_deplib "*) ;;
+               *)
+                       tmp_deplibs="$tmp_deplibs $test_deplib"
+                       ;;
+               esac
+       done
+       deplibs="$tmp_deplibs"
+
+       if test -n "$convenience"; then
+         if test -n "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+         else
+           gentop="$output_objdir/${outputname}x"
+           generated="$generated $gentop"
+
+           func_extract_archives $gentop $convenience
+           libobjs="$libobjs $func_extract_archives_result"
+         fi
+       fi
+       
+       if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+         eval flag=\"$thread_safe_flag_spec\"
+         linker_flags="$linker_flags $flag"
+       fi
+
+       # Make a backup of the uninstalled library when relinking
+       if test "$mode" = relink; then
+         $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+       fi
+
+       # Do each of the archive commands.
+       if test "$module" = yes && test -n "$module_cmds" ; then
+         if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+           eval test_cmds=\"$module_expsym_cmds\"
+           cmds=$module_expsym_cmds
+         else
+           eval test_cmds=\"$module_cmds\"
+           cmds=$module_cmds
+         fi
+       else
+       if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+         eval test_cmds=\"$archive_expsym_cmds\"
+         cmds=$archive_expsym_cmds
+       else
+         eval test_cmds=\"$archive_cmds\"
+         cmds=$archive_cmds
+         fi
+       fi
+
+       if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+          test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         :
+       else
+         # The command line is too long to link in one step, link piecewise.
+         $echo "creating reloadable object files..."
+
+         # Save the value of $output and $libobjs because we want to
+         # use them later.  If we have whole_archive_flag_spec, we
+         # want to use save_libobjs as it was before
+         # whole_archive_flag_spec was expanded, because we can't
+         # assume the linker understands whole_archive_flag_spec.
+         # This may have to be revisited, in case too many
+         # convenience libraries get linked in and end up exceeding
+         # the spec.
+         if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+         fi
+         save_output=$output
+         output_la=`$echo "X$output" | $Xsed -e "$basename"`
+
+         # Clear the reloadable object creation command queue and
+         # initialize k to one.
+         test_cmds=
+         concat_cmds=
+         objlist=
+         delfiles=
+         last_robj=
+         k=1
+         output=$output_objdir/$output_la-${k}.$objext
+         # Loop over the list of objects to be linked.
+         for obj in $save_libobjs
+         do
+           eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+           if test "X$objlist" = X ||
+              { len=`expr "X$test_cmds" : ".*"` &&
+                test "$len" -le "$max_cmd_len"; }; then
+             objlist="$objlist $obj"
+           else
+             # The command $test_cmds is almost too long, add a
+             # command to the queue.
+             if test "$k" -eq 1 ; then
+               # The first file doesn't have a previous command to add.
+               eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+             else
+               # All subsequent reloadable object files will link in
+               # the last one created.
+               eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+             fi
+             last_robj=$output_objdir/$output_la-${k}.$objext
+             k=`expr $k + 1`
+             output=$output_objdir/$output_la-${k}.$objext
+             objlist=$obj
+             len=1
+           fi
+         done
+         # Handle the remaining objects by creating one last
+         # reloadable object file.  All subsequent reloadable object
+         # files will link in the last one created.
+         test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+         eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+         if ${skipped_export-false}; then
+           $show "generating symbol list for \`$libname.la'"
+           export_symbols="$output_objdir/$libname.exp"
+           $run $rm $export_symbols
+           libobjs=$output
+           # Append the command to create the export file.
+           eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+          fi
+
+         # Set up a command to remove the reloadable object files
+         # after they are used.
+         i=0
+         while test "$i" -lt "$k"
+         do
+           i=`expr $i + 1`
+           delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
+         done
+
+         $echo "creating a temporary reloadable object file: $output"
+
+         # Loop through the commands generated above and execute them.
+         save_ifs="$IFS"; IFS='~'
+         for cmd in $concat_cmds; do
+           IFS="$save_ifs"
+           $show "$cmd"
+           $run eval "$cmd" || exit $?
+         done
+         IFS="$save_ifs"
+
+         libobjs=$output
+         # Restore the value of output.
+         output=$save_output
+
+         if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+         fi
+         # Expand the library linking commands again to reset the
+         # value of $libobjs for piecewise linking.
+
+         # Do each of the archive commands.
+         if test "$module" = yes && test -n "$module_cmds" ; then
+           if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+             cmds=$module_expsym_cmds
+           else
+             cmds=$module_cmds
+           fi
+         else
+         if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+           cmds=$archive_expsym_cmds
+         else
+           cmds=$archive_cmds
+           fi
+         fi
+
+         # Append the command to remove the reloadable object files
+         # to the just-reset $cmds.
+         eval cmds=\"\$cmds~\$rm $delfiles\"
+       fi
+       save_ifs="$IFS"; IFS='~'
+       for cmd in $cmds; do
+         IFS="$save_ifs"
+         eval cmd=\"$cmd\"
+         $show "$cmd"
+         $run eval "$cmd" || exit $?
+       done
+       IFS="$save_ifs"
+
+       # Restore the uninstalled library and exit
+       if test "$mode" = relink; then
+         $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+         exit $EXIT_SUCCESS
+       fi
+
+       # Create links to the real library.
+       for linkname in $linknames; do
+         if test "$realname" != "$linkname"; then
+           $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+           $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+         fi
+       done
+
+       # If -module or -export-dynamic was specified, set the dlname.
+       if test "$module" = yes || test "$export_dynamic" = yes; then
+         # On all known operating systems, these are identical.
+         dlname="$soname"
+       fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$deplibs"; then
+       $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+       $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+       $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+      fi
+
+      case $output in
+      *.lo)
+       if test -n "$objs$old_deplibs"; then
+         $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+         exit $EXIT_FAILURE
+       fi
+       libobj="$output"
+       obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+       ;;
+      *)
+       libobj=
+       obj="$output"
+       ;;
+      esac
+
+      # Delete the old objects.
+      $run $rm $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec
+      wl=
+
+      if test -n "$convenience"; then
+       if test -n "$whole_archive_flag_spec"; then
+         eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+       else
+         gentop="$output_objdir/${obj}x"
+         generated="$generated $gentop"
+
+         func_extract_archives $gentop $convenience
+         reload_conv_objs="$reload_objs $func_extract_archives_result"
+       fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      cmds=$reload_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+       IFS="$save_ifs"
+       eval cmd=\"$cmd\"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+       if test -n "$gentop"; then
+         $show "${rm}r $gentop"
+         $run ${rm}r $gentop
+       fi
+
+       exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+       if test -n "$gentop"; then
+         $show "${rm}r $gentop"
+         $run ${rm}r $gentop
+       fi
+
+       # Create an invalid libtool object if no PIC, so that we don't
+       # accidentally link it into a program.
+       # $show "echo timestamp > $libobj"
+       # $run eval "echo timestamp > $libobj" || exit $?
+       exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+       # Only do commands if we really have different PIC objects.
+       reload_objs="$libobjs $reload_conv_objs"
+       output="$libobj"
+       cmds=$reload_cmds
+       save_ifs="$IFS"; IFS='~'
+       for cmd in $cmds; do
+         IFS="$save_ifs"
+         eval cmd=\"$cmd\"
+         $show "$cmd"
+         $run eval "$cmd" || exit $?
+       done
+       IFS="$save_ifs"
+      fi
+
+      if test -n "$gentop"; then
+       $show "${rm}r $gentop"
+       $run ${rm}r $gentop
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+       *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+      esac
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+      fi
+
+      if test "$preload" = yes; then
+       if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+          test "$dlopen_self_static" = unknown; then
+         $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+       fi
+      fi
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+       # On Rhapsody replace the C library is the System framework
+       compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+       finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+       ;;
+      esac
+
+      case $host in
+      *darwin*)
+        # Don't allow lazy linking, it breaks C++ global constructors
+        if test "$tagname" = CXX ; then
+        compile_command="$compile_command ${wl}-bind_at_load"
+        finalize_command="$finalize_command ${wl}-bind_at_load"
+        fi
+        ;;
+      esac
+
+      compile_command="$compile_command $compile_deplibs"
+      finalize_command="$finalize_command $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       for libdir in $rpath $xrpath; do
+         # This is the magic to use -rpath.
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) finalize_rpath="$finalize_rpath $libdir" ;;
+         esac
+       done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           rpath="$rpath $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$perm_rpath " in
+         *" $libdir "*) ;;
+         *) perm_rpath="$perm_rpath $libdir" ;;
+         esac
+       fi
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+         case :$dllsearchpath: in
+         *":$libdir:"*) ;;
+         *) dllsearchpath="$dllsearchpath:$libdir";;
+         esac
+         ;;
+       esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           rpath="$rpath $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$finalize_perm_rpath " in
+         *" $libdir "*) ;;
+         *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+         esac
+       fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+       # Transform all the library objects into standard objects.
+       compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+       finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+      fi
+
+      dlsyms=
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       if test -n "$NM" && test -n "$global_symbol_pipe"; then
+         dlsyms="${outputname}S.c"
+       else
+         $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+       fi
+      fi
+
+      if test -n "$dlsyms"; then
+       case $dlsyms in
+       "") ;;
+       *.c)
+         # Discover the nlist of each of the dlfiles.
+         nlist="$output_objdir/${outputname}.nm"
+
+         $show "$rm $nlist ${nlist}S ${nlist}T"
+         $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+         # Parse the name list into a source file.
+         $show "creating $output_objdir/$dlsyms"
+
+         test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+         if test "$dlself" = yes; then
+           $show "generating symbol list for \`$output'"
+
+           test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+           # Add our own program objects to the symbol list.
+           progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+           for arg in $progfiles; do
+             $show "extracting global C symbols from \`$arg'"
+             $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+           done
+
+           if test -n "$exclude_expsyms"; then
+             $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+             $run eval '$mv "$nlist"T "$nlist"'
+           fi
+
+           if test -n "$export_symbols_regex"; then
+             $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+             $run eval '$mv "$nlist"T "$nlist"'
+           fi
+
+           # Prepare the list of exported symbols
+           if test -z "$export_symbols"; then
+             export_symbols="$output_objdir/$outputname.exp"
+             $run $rm $export_symbols
+             $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+           else
+             $run eval "${SED} -e 's/\([ ][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+             $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+             $run eval 'mv "$nlist"T "$nlist"'
+           fi
+         fi
+
+         for arg in $dlprefiles; do
+           $show "extracting global C symbols from \`$arg'"
+           name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+           $run eval '$echo ": $name " >> "$nlist"'
+           $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+         done
+
+         if test -z "$run"; then
+           # Make sure we have at least an empty file.
+           test -f "$nlist" || : > "$nlist"
+
+           if test -n "$exclude_expsyms"; then
+             $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+             $mv "$nlist"T "$nlist"
+           fi
+
+           # Try sorting and uniquifying the output.
+           if grep -v "^: " < "$nlist" |
+               if sort -k 3 </dev/null >/dev/null 2>&1; then
+                 sort -k 3
+               else
+                 sort +2
+               fi |
+               uniq > "$nlist"S; then
+             :
+           else
+             grep -v "^: " < "$nlist" > "$nlist"S
+           fi
+
+           if test -f "$nlist"S; then
+             eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+           else
+             $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+           fi
+
+           $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+"
+
+           case $host in
+           *cygwin* | *mingw* )
+         $echo >> "$output_objdir/$dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+   runtime relocations are performed -- see ld's documentation
+   on pseudo-relocs */
+struct {
+"
+             ;;
+           * )
+         $echo >> "$output_objdir/$dlsyms" "\
+const struct {
+"
+             ;;
+           esac
+
+
+         $echo >> "$output_objdir/$dlsyms" "\
+  const char *name;
+  lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+           eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+           $echo >> "$output_objdir/$dlsyms" "\
+  {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+         fi
+
+         pic_flag_for_symtable=
+         case $host in
+         # compiling the symbol table file with pic_flag works around
+         # a FreeBSD bug that causes programs to crash when -lm is
+         # linked before any other PIC object.  But we must not use
+         # pic_flag when linking with -static.  The problem exists in
+         # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+         *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+           case "$compile_command " in
+           *" -static "*) ;;
+           *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+           esac;;
+         *-*-hpux*)
+           case "$compile_command " in
+           *" -static "*) ;;
+           *) pic_flag_for_symtable=" $pic_flag";;
+           esac
+         esac
+
+         # Now compile the dynamic symbol file.
+         $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+         $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+         # Clean up the generated files.
+         $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+         $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+         # Transform the symbol file into the correct name.
+         compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+         finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+         ;;
+       *)
+         $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+      else
+       # We keep going just in case the user didn't refer to
+       # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+       # really was required.
+
+       # Nullify the symbol file.
+       compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+       finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+       # Replace the output file specification.
+       compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+       link_command="$compile_command$compile_rpath"
+
+       # We have no uninstalled library dependencies, so finalize right now.
+       $show "$link_command"
+       $run eval "$link_command"
+       status=$?
+
+       # Delete the generated files.
+       if test -n "$dlsyms"; then
+         $show "$rm $output_objdir/${outputname}S.${objext}"
+         $run $rm "$output_objdir/${outputname}S.${objext}"
+       fi
+
+       exit $status
+      fi
+
+      if test -n "$shlibpath_var"; then
+       # We should set the shlibpath_var
+       rpath=
+       for dir in $temp_rpath; do
+         case $dir in
+         [\\/]* | [A-Za-z]:[\\/]*)
+           # Absolute path.
+           rpath="$rpath$dir:"
+           ;;
+         *)
+           # Relative path: add a thisdir entry.
+           rpath="$rpath\$thisdir/$dir:"
+           ;;
+         esac
+       done
+       temp_rpath="$rpath"
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+       compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+       finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+       if test -n "$perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $perm_rpath; do
+           rpath="$rpath$dir:"
+         done
+         compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+       if test -n "$finalize_perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $finalize_perm_rpath; do
+           rpath="$rpath$dir:"
+         done
+         finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+      fi
+
+      if test "$no_install" = yes; then
+       # We don't need to create a wrapper script.
+       link_command="$compile_var$compile_command$compile_rpath"
+       # Replace the output file specification.
+       link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+       # Delete the old output file.
+       $run $rm $output
+       # Link the executable and exit
+       $show "$link_command"
+       $run eval "$link_command" || exit $?
+       exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+       # Fast installation is not supported
+       link_command="$compile_var$compile_command$compile_rpath"
+       relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+       $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+       $echo "$modename: \`$output' will be relinked during installation" 1>&2
+      else
+       if test "$fast_install" != no; then
+         link_command="$finalize_var$compile_command$finalize_rpath"
+         if test "$fast_install" = yes; then
+           relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+         else
+           # fast_install is set to needless
+           relink_command=
+         fi
+       else
+         link_command="$compile_var$compile_command$compile_rpath"
+         relink_command="$finalize_var$finalize_command$finalize_rpath"
+       fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      $show "$link_command"
+      $run eval "$link_command" || exit $?
+
+      # Now create the wrapper script.
+      $show "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+       # Preserve any variables that may affect compiler behavior
+       for var in $variables_saved_for_relink; do
+         if eval test -z \"\${$var+set}\"; then
+           relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+         elif eval var_value=\$$var; test -z "$var_value"; then
+           relink_command="$var=; export $var; $relink_command"
+         else
+           var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+           relink_command="$var=\"$var_value\"; export $var; $relink_command"
+         fi
+       done
+       relink_command="(cd `pwd`; $relink_command)"
+       relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Quote $echo for shipping.
+      if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+       case $progpath in
+       [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+       *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+       esac
+       qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+      else
+       qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if our run command is non-null.
+      if test -z "$run"; then
+       # win32 will think the script is a binary if it has
+       # a .exe suffix, so we strip it off here.
+       case $output in
+         *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+       esac
+       # test for cygwin because mv fails w/o .exe extensions
+       case $host in
+         *cygwin*)
+           exeext=.exe
+           outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+         *) exeext= ;;
+       esac
+       case $host in
+         *cygwin* | *mingw* )
+           cwrappersource=`$echo ${objdir}/lt-${outputname}.c`
+           cwrapper=`$echo ${output}.exe`
+           $rm $cwrappersource $cwrapper
+           trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+           cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "/bin/sh $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+           cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+#define HAVE_DOS_BASED_FILE_SYSTEM
+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+        (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+char * basename (const char *name);
+char * fnqualify(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int i;
+
+  program_name = (char *) xstrdup ((char *) basename (argv[0]));
+  newargz = XMALLOC(char *, argc+2);
+EOF
+
+           cat >> $cwrappersource <<EOF
+  newargz[0] = "$SHELL";
+EOF
+
+           cat >> $cwrappersource <<"EOF"
+  newargz[1] = fnqualify(argv[0]);
+  /* we know the script has the same name, without the .exe */
+  /* so make sure newargz[1] doesn't end in .exe */
+  strendzap(newargz[1],".exe");
+  for (i = 1; i < argc; i++)
+    newargz[i+1] = xstrdup(argv[i]);
+  newargz[argc+1] = NULL;
+EOF
+
+           cat >> $cwrappersource <<EOF
+  execv("$SHELL",newargz);
+EOF
+
+           cat >> $cwrappersource <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void * p = (void *) malloc (num);
+  if (!p)
+    lt_fatal ("Memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+char *
+basename (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha (name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return (char *) base;
+}
+
+char *
+fnqualify(const char *path)
+{
+  size_t size;
+  char *p;
+  char tmp[LT_PATHMAX + 1];
+
+  assert(path != NULL);
+
+  /* Is it qualified already? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha (path[0]) && path[1] == ':')
+    return xstrdup (path);
+#endif
+  if (IS_DIR_SEPARATOR (path[0]))
+    return xstrdup (path);
+
+  /* prepend the current directory */
+  /* doesn't handle '~' */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal ("getcwd failed");
+  size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
+  p = XMALLOC(char, size);
+  sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
+  return p;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert(str != NULL);
+  assert(pat != NULL);
+
+  len = strlen(str);
+  patlen = strlen(pat);
+
+  if (patlen <= len)
+  {
+    str += len - patlen;
+    if (strcmp(str, pat) == 0)
+      *str = '\0';
+  }
+  return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+          const char * message, va_list ap)
+{
+  fprintf (stderr, "%s: %s: ", program_name, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  va_end (ap);
+}
+EOF
+         # we should really use a build-platform specific compiler
+         # here, but OTOH, the wrappers (shell script and this C one)
+         # are only useful if you want to execute the "real" binary.
+         # Since the "real" binary is built for $host, then this
+         # wrapper might as well be built for $host, too.
+         $run $LTCC -s -o $cwrapper $cwrappersource
+         ;;
+       esac
+       $rm $output
+       trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+       $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variable:
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$echo are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    echo=\"$qecho\"
+    file=\"\$0\"
+    # Make sure echo works.
+    if test \"X\$1\" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+      # Yippee, \$echo works!
+      :
+    else
+      # Restart under the correct shell, and then maybe \$echo will work.
+      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+    fi
+  fi\
+"
+       $echo >> $output "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+       if test "$fast_install" = yes; then
+         $echo >> $output "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" || \\
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $mkdir \"\$progdir\"
+    else
+      $rm \"\$progdir/\$file\"
+    fi"
+
+         $echo >> $output "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+       $echo \"\$relink_command_output\" >&2
+       $rm \"\$progdir/\$file\"
+       exit $EXIT_FAILURE
+      fi
+    fi
+
+    $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $rm \"\$progdir/\$program\";
+      $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $rm \"\$progdir/\$file\"
+  fi"
+       else
+         $echo >> $output "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+       fi
+
+       $echo >> $output "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+       # Export our shlibpath_var if we have one.
+       if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+         $echo >> $output "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+       fi
+
+       # fixup the dll searchpath if we need to.
+       if test -n "$dllsearchpath"; then
+         $echo >> $output "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+       fi
+
+       $echo >> $output "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+"
+       case $host in
+       # Backslashes separate directories on plain windows
+       *-*-mingw | *-*-os2*)
+         $echo >> $output "\
+      exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+         ;;
+
+       *)
+         $echo >> $output "\
+      exec \$progdir/\$program \${1+\"\$@\"}
+"
+         ;;
+       esac
+       $echo >> $output "\
+      \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+      exit $EXIT_FAILURE
+    fi
+  else
+    # The program doesn't exist.
+    \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+    \$echo \"This script is just a wrapper for \$program.\" 1>&2
+    $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi\
+"
+       chmod +x $output
+      fi
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+       oldobjs="$libobjs_save"
+       addlibs="$convenience"
+       build_libtool_libs=no
+      else
+       if test "$build_libtool_libs" = module; then
+         oldobjs="$libobjs_save"
+         build_libtool_libs=no
+       else
+         oldobjs="$old_deplibs $non_pic_objects"
+       fi
+       addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+       gentop="$output_objdir/${outputname}x"
+       generated="$generated $gentop"
+
+       func_extract_archives $gentop $addlibs
+       oldobjs="$oldobjs $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       cmds=$old_archive_from_new_cmds
+      else
+       # POSIX demands no paths to be encoded in archives.  We have
+       # to avoid creating archives with duplicate basenames if we
+       # might have to extract them afterwards, e.g., when creating a
+       # static archive out of a convenience library, or when linking
+       # the entirety of a libtool archive into another (currently
+       # not supported by libtool).
+       if (for obj in $oldobjs
+           do
+             $echo "X$obj" | $Xsed -e 's%^.*/%%'
+           done | sort | sort -uc >/dev/null 2>&1); then
+         :
+       else
+         $echo "copying selected object files to avoid basename conflicts..."
+
+         if test -z "$gentop"; then
+           gentop="$output_objdir/${outputname}x"
+           generated="$generated $gentop"
+
+           $show "${rm}r $gentop"
+           $run ${rm}r "$gentop"
+           $show "$mkdir $gentop"
+           $run $mkdir "$gentop"
+           status=$?
+           if test "$status" -ne 0 && test ! -d "$gentop"; then
+             exit $status
+           fi
+         fi
+
+         save_oldobjs=$oldobjs
+         oldobjs=
+         counter=1
+         for obj in $save_oldobjs
+         do
+           objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+           case " $oldobjs " in
+           " ") oldobjs=$obj ;;
+           *[\ /]"$objbase "*)
+             while :; do
+               # Make sure we don't pick an alternate name that also
+               # overlaps.
+               newobj=lt$counter-$objbase
+               counter=`expr $counter + 1`
+               case " $oldobjs " in
+               *[\ /]"$newobj "*) ;;
+               *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+               esac
+             done
+             $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+             $run ln "$obj" "$gentop/$newobj" ||
+             $run cp "$obj" "$gentop/$newobj"
+             oldobjs="$oldobjs $gentop/$newobj"
+             ;;
+           *) oldobjs="$oldobjs $obj" ;;
+           esac
+         done
+       fi
+
+       eval cmds=\"$old_archive_cmds\"
+
+       if len=`expr "X$cmds" : ".*"` &&
+            test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         cmds=$old_archive_cmds
+       else
+         # the command line is too long to link in one step, link in parts
+         $echo "using piecewise archive linking..."
+         save_RANLIB=$RANLIB
+         RANLIB=:
+         objlist=
+         concat_cmds=
+         save_oldobjs=$oldobjs
+
+         # Is there a better way of finding the last object in the list?
+         for obj in $save_oldobjs
+         do
+           last_oldobj=$obj
+         done
+         for obj in $save_oldobjs
+         do
+           oldobjs="$objlist $obj"
+           objlist="$objlist $obj"
+           eval test_cmds=\"$old_archive_cmds\"
+           if len=`expr "X$test_cmds" : ".*"` &&
+              test "$len" -le "$max_cmd_len"; then
+             :
+           else
+             # the above command should be used before it gets too long
+             oldobjs=$objlist
+             if test "$obj" = "$last_oldobj" ; then
+               RANLIB=$save_RANLIB
+             fi
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+             objlist=
+           fi
+         done
+         RANLIB=$save_RANLIB
+         oldobjs=$objlist
+         if test "X$oldobjs" = "X" ; then
+           eval cmds=\"\$concat_cmds\"
+         else
+           eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+         fi
+       fi
+      fi
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+        eval cmd=\"$cmd\"
+       IFS="$save_ifs"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$generated"; then
+      $show "${rm}r$generated"
+      $run ${rm}r$generated
+    fi
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      $show "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+       if eval test -z \"\${$var+set}\"; then
+         relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+       elif eval var_value=\$$var; test -z "$var_value"; then
+         relink_command="$var=; export $var; $relink_command"
+       else
+         var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+         relink_command="$var=\"$var_value\"; export $var; $relink_command"
+       fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+       relink_command=
+      fi
+
+
+      # Only create the output if not a dry run.
+      if test -z "$run"; then
+       for installed in no yes; do
+         if test "$installed" = yes; then
+           if test -z "$install_libdir"; then
+             break
+           fi
+           output="$output_objdir/$outputname"i
+           # Replace all uninstalled libtool libraries with the installed ones
+           newdependency_libs=
+           for deplib in $dependency_libs; do
+             case $deplib in
+             *.la)
+               name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+               eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+               if test -z "$libdir"; then
+                 $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+                 exit $EXIT_FAILURE
+               fi
+               newdependency_libs="$newdependency_libs $libdir/$name"
+               ;;
+             *) newdependency_libs="$newdependency_libs $deplib" ;;
+             esac
+           done
+           dependency_libs="$newdependency_libs"
+           newdlfiles=
+           for lib in $dlfiles; do
+             name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+             eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+             if test -z "$libdir"; then
+               $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+               exit $EXIT_FAILURE
+             fi
+             newdlfiles="$newdlfiles $libdir/$name"
+           done
+           dlfiles="$newdlfiles"
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+             eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+             if test -z "$libdir"; then
+               $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+               exit $EXIT_FAILURE
+             fi
+             newdlprefiles="$newdlprefiles $libdir/$name"
+           done
+           dlprefiles="$newdlprefiles"
+         else
+           newdlfiles=
+           for lib in $dlfiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             newdlfiles="$newdlfiles $abs"
+           done
+           dlfiles="$newdlfiles"
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             newdlprefiles="$newdlprefiles $abs"
+           done
+           dlprefiles="$newdlprefiles"
+         fi
+         $rm $output
+         # place dlname in correct position for cygwin
+         tdlname=$dlname
+         case $host,$output,$installed,$module,$dlname in
+           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+         esac
+         $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+         if test "$installed" = no && test "$need_relink" = yes; then
+           $echo >> $output "\
+relink_command=\"$relink_command\""
+         fi
+       done
+      fi
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+      $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool install mode
+  install)
+    modename="$modename: install"
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+      # Aesthetically quote it.
+      arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$arg "
+      arg="$1"
+      shift
+    else
+      install_prog=
+      arg="$nonopt"
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+    case $arg in
+    *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+      arg="\"$arg\""
+      ;;
+    esac
+    install_prog="$install_prog$arg"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+       files="$files $dest"
+       dest="$arg"
+       continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f) prev="-f" ;;
+      -g) prev="-g" ;;
+      -m) prev="-m" ;;
+      -o) prev="-o" ;;
+      -s)
+       stripme=" -s"
+       continue
+       ;;
+      -*) ;;
+
+      *)
+       # If the previous option needed an argument, then skip it.
+       if test -n "$prev"; then
+         prev=
+       else
+         dest="$arg"
+         continue
+       fi
+       ;;
+      esac
+
+      # Aesthetically quote the argument.
+      arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$install_prog $arg"
+    done
+
+    if test -z "$install_prog"; then
+      $echo "$modename: you must specify an install program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prev' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+       $echo "$modename: no file or destination specified" 1>&2
+      else
+       $echo "$modename: you must specify a destination" 1>&2
+      fi
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Strip any trailing slash from the destination.
+    dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$destdir" = "X$dest" && destdir=.
+      destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files
+      if test "$#" -gt 2; then
+       $echo "$modename: \`$dest' is not a directory" 1>&2
+       $echo "$help" 1>&2
+       exit $EXIT_FAILURE
+      fi
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+       case $file in
+       *.lo) ;;
+       *)
+         $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+       # Do the static libraries later.
+       staticlibs="$staticlibs $file"
+       ;;
+
+      *.la)
+       # Check to see that this really is a libtool archive.
+       if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       library_names=
+       old_library=
+       relink_command=
+       # If there is no directory component, then add one.
+       case $file in
+       */* | *\\*) . $file ;;
+       *) . ./$file ;;
+       esac
+
+       # Add the libdir to current_libdirs if it is the destination.
+       if test "X$destdir" = "X$libdir"; then
+         case "$current_libdirs " in
+         *" $libdir "*) ;;
+         *) current_libdirs="$current_libdirs $libdir" ;;
+         esac
+       else
+         # Note the libdir as a future libdir.
+         case "$future_libdirs " in
+         *" $libdir "*) ;;
+         *) future_libdirs="$future_libdirs $libdir" ;;
+         esac
+       fi
+
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+       test "X$dir" = "X$file/" && dir=
+       dir="$dir$objdir"
+
+       if test -n "$relink_command"; then
+         # Determine the prefix the user has applied to our future dir.
+         inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+         # Don't allow the user to place us outside of our expected
+         # location b/c this prevents finding dependent libraries that
+         # are installed to the same prefix.
+         # At present, this check doesn't affect windows .dll's that
+         # are installed into $libdir/../bin (currently, that works fine)
+         # but it's something to keep an eye on.
+         if test "$inst_prefix_dir" = "$destdir"; then
+           $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+           exit $EXIT_FAILURE
+         fi
+
+         if test -n "$inst_prefix_dir"; then
+           # Stick the inst_prefix_dir data into the link command.
+           relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+         else
+           relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+         fi
+
+         $echo "$modename: warning: relinking \`$file'" 1>&2
+         $show "$relink_command"
+         if $run eval "$relink_command"; then :
+         else
+           $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+           exit $EXIT_FAILURE
+         fi
+       fi
+
+       # See the names of the shared library.
+       set dummy $library_names
+       if test -n "$2"; then
+         realname="$2"
+         shift
+         shift
+
+         srcname="$realname"
+         test -n "$relink_command" && srcname="$realname"T
+
+         # Install the shared library and build the symlinks.
+         $show "$install_prog $dir/$srcname $destdir/$realname"
+         $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+         if test -n "$stripme" && test -n "$striplib"; then
+           $show "$striplib $destdir/$realname"
+           $run eval "$striplib $destdir/$realname" || exit $?
+         fi
+
+         if test "$#" -gt 0; then
+           # Delete the old symlinks, and create new ones.
+           for linkname
+           do
+             if test "$linkname" != "$realname"; then
+               $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+               $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+             fi
+           done
+         fi
+
+         # Do each command in the postinstall commands.
+         lib="$destdir/$realname"
+         cmds=$postinstall_cmds
+         save_ifs="$IFS"; IFS='~'
+         for cmd in $cmds; do
+           IFS="$save_ifs"
+           eval cmd=\"$cmd\"
+           $show "$cmd"
+           $run eval "$cmd" || exit $?
+         done
+         IFS="$save_ifs"
+       fi
+
+       # Install the pseudo-library for information purposes.
+       name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+       instname="$dir/$name"i
+       $show "$install_prog $instname $destdir/$name"
+       $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+       # Maybe install the static library, too.
+       test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+       ;;
+
+      *.lo)
+       # Install (i.e. copy) a libtool object.
+
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+         destfile="$destdir/$destfile"
+       fi
+
+       # Deduce the name of the destination old-style object file.
+       case $destfile in
+       *.lo)
+         staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+         ;;
+       *.$objext)
+         staticdest="$destfile"
+         destfile=
+         ;;
+       *)
+         $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+         ;;
+       esac
+
+       # Install the libtool object if requested.
+       if test -n "$destfile"; then
+         $show "$install_prog $file $destfile"
+         $run eval "$install_prog $file $destfile" || exit $?
+       fi
+
+       # Install the old object if enabled.
+       if test "$build_old_libs" = yes; then
+         # Deduce the name of the old-style object file.
+         staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+         $show "$install_prog $staticobj $staticdest"
+         $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+       fi
+       exit $EXIT_SUCCESS
+       ;;
+
+      *)
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+         destfile="$destdir/$destfile"
+       fi
+
+       # If the file is missing, and there is a .exe on the end, strip it
+       # because it is most likely a libtool script we actually want to
+       # install
+       stripped_ext=""
+       case $file in
+         *.exe)
+           if test ! -f "$file"; then
+             file=`$echo $file|${SED} 's,.exe$,,'`
+             stripped_ext=".exe"
+           fi
+           ;;
+       esac
+
+       # Do a test to see if this is really a libtool program.
+       case $host in
+       *cygwin*|*mingw*)
+           wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+           ;;
+       *)
+           wrapper=$file
+           ;;
+       esac
+       if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+         notinst_deplibs=
+         relink_command=
+
+         # To insure that "foo" is sourced, and not "foo.exe",
+         # finese the cygwin/MSYS system by explicitly sourcing "foo."
+         # which disallows the automatic-append-.exe behavior.
+         case $build in
+         *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+         *) wrapperdot=${wrapper} ;;
+         esac
+         # If there is no directory component, then add one.
+         case $file in
+         */* | *\\*) . ${wrapperdot} ;;
+         *) . ./${wrapperdot} ;;
+         esac
+
+         # Check the variables that should have been set.
+         if test -z "$notinst_deplibs"; then
+           $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+           exit $EXIT_FAILURE
+         fi
+
+         finalize=yes
+         for lib in $notinst_deplibs; do
+           # Check to see that each library is installed.
+           libdir=
+           if test -f "$lib"; then
+             # If there is no directory component, then add one.
+             case $lib in
+             */* | *\\*) . $lib ;;
+             *) . ./$lib ;;
+             esac
+           fi
+           libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+           if test -n "$libdir" && test ! -f "$libfile"; then
+             $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+             finalize=no
+           fi
+         done
+
+         relink_command=
+         # To insure that "foo" is sourced, and not "foo.exe",
+         # finese the cygwin/MSYS system by explicitly sourcing "foo."
+         # which disallows the automatic-append-.exe behavior.
+         case $build in
+         *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+         *) wrapperdot=${wrapper} ;;
+         esac
+         # If there is no directory component, then add one.
+         case $file in
+         */* | *\\*) . ${wrapperdot} ;;
+         *) . ./${wrapperdot} ;;
+         esac
+
+         outputname=
+         if test "$fast_install" = no && test -n "$relink_command"; then
+           if test "$finalize" = yes && test -z "$run"; then
+             tmpdir="/tmp"
+             test -n "$TMPDIR" && tmpdir="$TMPDIR"
+             tmpdir="$tmpdir/libtool-$$"
+             save_umask=`umask`
+             umask 0077
+             if $mkdir "$tmpdir"; then
+               umask $save_umask
+             else
+               umask $save_umask
+               $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+               continue
+             fi
+             file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+             outputname="$tmpdir/$file"
+             # Replace the output file specification.
+             relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+             $show "$relink_command"
+             if $run eval "$relink_command"; then :
+             else
+               $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+               ${rm}r "$tmpdir"
+               continue
+             fi
+             file="$outputname"
+           else
+             $echo "$modename: warning: cannot relink \`$file'" 1>&2
+           fi
+         else
+           # Install the binary that we compiled earlier.
+           file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+         fi
+       fi
+
+       # remove .exe since cygwin /usr/bin/install will append another
+       # one anyways
+       case $install_prog,$host in
+       */usr/bin/install*,*cygwin*)
+         case $file:$destfile in
+         *.exe:*.exe)
+           # this is ok
+           ;;
+         *.exe:*)
+           destfile=$destfile.exe
+           ;;
+         *:*.exe)
+           destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+           ;;
+         esac
+         ;;
+       esac
+       $show "$install_prog$stripme $file $destfile"
+       $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+       test -n "$outputname" && ${rm}r "$tmpdir"
+       ;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      $show "$install_prog $file $oldlib"
+      $run eval "$install_prog \$file \$oldlib" || exit $?
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+       $show "$old_striplib $oldlib"
+       $run eval "$old_striplib $oldlib" || exit $?
+      fi
+
+      # Do each command in the postinstall commands.
+      cmds=$old_postinstall_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+       IFS="$save_ifs"
+       eval cmd=\"$cmd\"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$future_libdirs"; then
+      $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+    fi
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      test -n "$run" && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool finish mode
+  finish)
+    modename="$modename: finish"
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+       libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+       if test -n "$finish_cmds"; then
+         # Do each command in the finish commands.
+         cmds=$finish_cmds
+         save_ifs="$IFS"; IFS='~'
+         for cmd in $cmds; do
+           IFS="$save_ifs"
+           eval cmd=\"$cmd\"
+           $show "$cmd"
+           $run eval "$cmd" || admincmds="$admincmds
+       $cmd"
+         done
+         IFS="$save_ifs"
+       fi
+       if test -n "$finish_eval"; then
+         # Do the single finish_eval.
+         eval cmds=\"$finish_eval\"
+         $run eval "$cmds" || admincmds="$admincmds
+       $cmds"
+       fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    test "$show" = : && exit $EXIT_SUCCESS
+
+    $echo "----------------------------------------------------------------------"
+    $echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      $echo "   $libdir"
+    done
+    $echo
+    $echo "If you ever happen to want to link against installed libraries"
+    $echo "in a given directory, LIBDIR, you must either use libtool, and"
+    $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    $echo "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      $echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      $echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      $echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      $echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      $echo "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      $echo "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      $echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    $echo
+    $echo "See any operating system documentation about shared libraries for"
+    $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+    $echo "----------------------------------------------------------------------"
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool execute mode
+  execute)
+    modename="$modename: execute"
+
+    # The first argument is the command name.
+    cmd="$nonopt"
+    if test -z "$cmd"; then
+      $echo "$modename: you must specify a COMMAND" 1>&2
+      $echo "$help"
+      exit $EXIT_FAILURE
+    fi
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      if test ! -f "$file"; then
+       $echo "$modename: \`$file' is not a file" 1>&2
+       $echo "$help" 1>&2
+       exit $EXIT_FAILURE
+      fi
+
+      dir=
+      case $file in
+      *.la)
+       # Check to see that this really is a libtool archive.
+       if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+         $echo "$help" 1>&2
+         exit $EXIT_FAILURE
+       fi
+
+       # Read the libtool library.
+       dlname=
+       library_names=
+
+       # If there is no directory component, then add one.
+       case $file in
+       */* | *\\*) . $file ;;
+       *) . ./$file ;;
+       esac
+
+       # Skip this library if it cannot be dlopened.
+       if test -z "$dlname"; then
+         # Warn if it was a shared library.
+         test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+         continue
+       fi
+
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+
+       if test -f "$dir/$objdir/$dlname"; then
+         dir="$dir/$objdir"
+       else
+         $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+         exit $EXIT_FAILURE
+       fi
+       ;;
+
+      *.lo)
+       # Just add the directory containing the .lo file.
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+       ;;
+
+      *)
+       $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+       continue
+       ;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+       eval "$shlibpath_var=\"\$dir\""
+      else
+       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -*) ;;
+      *)
+       # Do a test to see if this is really a libtool program.
+       if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         # If there is no directory component, then add one.
+         case $file in
+         */* | *\\*) . $file ;;
+         *) . ./$file ;;
+         esac
+
+         # Transform arg to wrapped name.
+         file="$progdir/$program"
+       fi
+       ;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+      args="$args \"$file\""
+    done
+
+    if test -z "$run"; then
+      if test -n "$shlibpath_var"; then
+       # Export the shlibpath_var.
+       eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      if test "${save_LC_ALL+set}" = set; then
+       LC_ALL="$save_LC_ALL"; export LC_ALL
+      fi
+      if test "${save_LANG+set}" = set; then
+       LANG="$save_LANG"; export LANG
+      fi
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+       eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+       $echo "export $shlibpath_var"
+      fi
+      $echo "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool clean and uninstall mode
+  clean | uninstall)
+    modename="$modename: $mode"
+    rm="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) rm="$rm $arg"; rmforce=yes ;;
+      -*) rm="$rm $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    if test -z "$rm"; then
+      $echo "$modename: you must specify an RM program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    rmdirs=
+
+    origobjdir="$objdir"
+    for file in $files; do
+      dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+      if test "X$dir" = "X$file"; then
+       dir=.
+       objdir="$origobjdir"
+      else
+       objdir="$dir/$origobjdir"
+      fi
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+      test "$mode" = uninstall && objdir="$dir"
+
+      # Remember objdir for removal later, being careful to avoid duplicates
+      if test "$mode" = clean; then
+       case " $rmdirs " in
+         *" $objdir "*) ;;
+         *) rmdirs="$rmdirs $objdir" ;;
+       esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if (test -L "$file") >/dev/null 2>&1 \
+       || (test -h "$file") >/dev/null 2>&1 \
+       || test -f "$file"; then
+       :
+      elif test -d "$file"; then
+       exit_status=1
+       continue
+      elif test "$rmforce" = yes; then
+       continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+       # Possibly a libtool archive, so verify it.
+       if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         . $dir/$name
+
+         # Delete the libtool libraries and symlinks.
+         for n in $library_names; do
+           rmfiles="$rmfiles $objdir/$n"
+         done
+         test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+         test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+         if test "$mode" = uninstall; then
+           if test -n "$library_names"; then
+             # Do each command in the postuninstall commands.
+             cmds=$postuninstall_cmds
+             save_ifs="$IFS"; IFS='~'
+             for cmd in $cmds; do
+               IFS="$save_ifs"
+               eval cmd=\"$cmd\"
+               $show "$cmd"
+               $run eval "$cmd"
+               if test "$?" -ne 0 && test "$rmforce" != yes; then
+                 exit_status=1
+               fi
+             done
+             IFS="$save_ifs"
+           fi
+
+           if test -n "$old_library"; then
+             # Do each command in the old_postuninstall commands.
+             cmds=$old_postuninstall_cmds
+             save_ifs="$IFS"; IFS='~'
+             for cmd in $cmds; do
+               IFS="$save_ifs"
+               eval cmd=\"$cmd\"
+               $show "$cmd"
+               $run eval "$cmd"
+               if test "$?" -ne 0 && test "$rmforce" != yes; then
+                 exit_status=1
+               fi
+             done
+             IFS="$save_ifs"
+           fi
+           # FIXME: should reinstall the best remaining shared library.
+         fi
+       fi
+       ;;
+
+      *.lo)
+       # Possibly a libtool object, so verify it.
+       if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+         # Read the .lo file
+         . $dir/$name
+
+         # Add PIC object to the list of files to remove.
+         if test -n "$pic_object" \
+            && test "$pic_object" != none; then
+           rmfiles="$rmfiles $dir/$pic_object"
+         fi
+
+         # Add non-PIC object to the list of files to remove.
+         if test -n "$non_pic_object" \
+            && test "$non_pic_object" != none; then
+           rmfiles="$rmfiles $dir/$non_pic_object"
+         fi
+       fi
+       ;;
+
+      *)
+       if test "$mode" = clean ; then
+         noexename=$name
+         case $file in
+         *.exe)
+           file=`$echo $file|${SED} 's,.exe$,,'`
+           noexename=`$echo $name|${SED} 's,.exe$,,'`
+           # $file with .exe has already been added to rmfiles,
+           # add $file without .exe
+           rmfiles="$rmfiles $file"
+           ;;
+         esac
+         # Do a test to see if this is a libtool program.
+         if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+           relink_command=
+           . $dir/$noexename
+
+           # note $name still contains .exe if it was in $file originally
+           # as does the version of $file that was added into $rmfiles
+           rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+           if test "$fast_install" = yes && test -n "$relink_command"; then
+             rmfiles="$rmfiles $objdir/lt-$name"
+           fi
+           if test "X$noexename" != "X$name" ; then
+             rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+           fi
+         fi
+       fi
+       ;;
+      esac
+      $show "$rm $rmfiles"
+      $run $rm $rmfiles || exit_status=1
+    done
+    objdir="$origobjdir"
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+       $show "rmdir $dir"
+       $run rmdir $dir >/dev/null 2>&1
+      fi
+    done
+
+    exit $exit_status
+    ;;
+
+  "")
+    $echo "$modename: you must specify a MODE" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+  esac
+
+  if test -z "$exec_cmd"; then
+    $echo "$modename: invalid operation mode \`$mode'" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+  eval exec $exec_cmd
+  exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+    --config          show all configuration variables
+    --debug           enable verbose shell tracing
+-n, --dry-run         display commands without modifying any files
+    --features        display basic configuration information and exit
+    --finish          same as \`--mode=finish'
+    --help            display this help message and exit
+    --mode=MODE       use operation mode MODE [default=inferred from MODE-ARGS]
+    --quiet           same as \`--silent'
+    --silent          don't print informational messages
+    --tag=TAG         use configuration variables from tag TAG
+    --version         print version information
+
+MODE must be one of the following:
+
+      clean           remove files from the build directory
+      compile         compile a source file into a libtool object
+      execute         automatically set library path, then run a program
+      finish          complete the installation of libtool libraries
+      install         install libraries or executables
+      link            create a library or an executable
+      uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool@gnu.org>."
+  exit $EXIT_SUCCESS
+  ;;
+
+clean)
+  $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+compile)
+  $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -prefer-pic       try to building PIC objects only
+  -prefer-non-pic   try to building non-PIC objects only
+  -static           always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+  ;;
+
+execute)
+  $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+  ;;
+
+finish)
+  $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+  ;;
+
+install)
+  $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+  ;;
+
+link)
+  $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                   try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                   try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -static           do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                   specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+  ;;
+
+uninstall)
+  $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+*)
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+  ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $?
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/m4/Makefile.am b/m4/Makefile.am
new file mode 100644 (file)
index 0000000..8c59b9e
--- /dev/null
@@ -0,0 +1,20 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       ogg.m4 \
+       xmms.m4
diff --git a/m4/ogg.m4 b/m4/ogg.m4
new file mode 100644 (file)
index 0000000..0e1f1ab
--- /dev/null
+++ b/m4/ogg.m4
@@ -0,0 +1,102 @@
+# Configure paths for libogg
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_OGG],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ogg,[  --with-ogg=PFX   Prefix where libogg is installed (optional)], ogg_prefix="$withval", ogg_prefix="")
+AC_ARG_WITH(ogg-libraries,[  --with-ogg-libraries=DIR   Directory where libogg library is installed (optional)], ogg_libraries="$withval", ogg_libraries="")
+AC_ARG_WITH(ogg-includes,[  --with-ogg-includes=DIR   Directory where libogg header files are installed (optional)], ogg_includes="$withval", ogg_includes="")
+AC_ARG_ENABLE(oggtest, [  --disable-oggtest       Do not try to compile and run a test Ogg program],, enable_oggtest=yes)
+
+  if test "x$ogg_libraries" != "x" ; then
+    OGG_LIBS="-L$ogg_libraries"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_LIBS="-L$ogg_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    OGG_LIBS="-L$prefix/lib"
+  fi
+
+  OGG_LIBS="$OGG_LIBS -logg"
+
+  if test "x$ogg_includes" != "x" ; then
+    OGG_CFLAGS="-I$ogg_includes"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_CFLAGS="-I$ogg_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    OGG_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Ogg)
+  no_ogg=""
+
+
+  if test "x$enable_oggtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Ogg is sufficiently new.
+dnl
+      rm -f conf.oggtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+int main ()
+{
+  system("touch conf.oggtest");
+  return 0;
+}
+
+],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ogg" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.oggtest ; then
+       :
+     else
+       echo "*** Could not run Ogg test program, checking why..."
+       CFLAGS="$CFLAGS $OGG_CFLAGS"
+       LIBS="$LIBS $OGG_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <ogg/ogg.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Ogg or finding the wrong"
+       echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means Ogg was incorrectly installed"
+       echo "*** or that you have moved Ogg since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     OGG_CFLAGS=""
+     OGG_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(OGG_CFLAGS)
+  AC_SUBST(OGG_LIBS)
+  rm -f conf.oggtest
+])
diff --git a/m4/xmms.m4 b/m4/xmms.m4
new file mode 100644 (file)
index 0000000..f4c03a7
--- /dev/null
@@ -0,0 +1,148 @@
+# CFLAGS and library paths for XMMS
+# written 15 December 1999 by Ben Gertzfield <che@debian.org>
+
+dnl Usage:
+dnl AM_PATH_XMMS([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl
+dnl Example:
+dnl AM_PATH_XMMS(0.9.5.1, , AC_MSG_ERROR([*** XMMS >= 0.9.5.1 not installed - please install first ***]))
+dnl
+dnl Defines XMMS_CFLAGS, XMMS_LIBS, XMMS_DATA_DIR, XMMS_PLUGIN_DIR, 
+dnl XMMS_VISUALIZATION_PLUGIN_DIR, XMMS_INPUT_PLUGIN_DIR, 
+dnl XMMS_OUTPUT_PLUGIN_DIR, XMMS_GENERAL_PLUGIN_DIR, XMMS_EFFECT_PLUGIN_DIR,
+dnl and XMMS_VERSION for your plugin pleasure.
+dnl
+
+dnl XMMS_TEST_VERSION(AVAILABLE-VERSION, NEEDED-VERSION [, ACTION-IF-OKAY [, ACTION-IF-NOT-OKAY]])
+AC_DEFUN([XMMS_TEST_VERSION], [
+
+# Determine which version number is greater. Prints 2 to stdout if     
+# the second number is greater, 1 if the first number is greater,      
+# 0 if the numbers are equal.                                          
+                                                                       
+# Written 15 December 1999 by Ben Gertzfield <che@debian.org>          
+# Revised 15 December 1999 by Jim Monty <monty@primenet.com>           
+                                                                       
+    AC_PROG_AWK
+    xmms_got_version=[` $AWK '                                         \
+BEGIN {                                                                        \
+    print vercmp(ARGV[1], ARGV[2]);                                    \
+}                                                                      \
+                                                                       \
+function vercmp(ver1, ver2,    ver1arr, ver2arr,                       \
+                               ver1len, ver2len,                       \
+                               ver1int, ver2int, len, i, p) {          \
+                                                                       \
+    ver1len = split(ver1, ver1arr, /\./);                              \
+    ver2len = split(ver2, ver2arr, /\./);                              \
+                                                                       \
+    len = ver1len > ver2len ? ver1len : ver2len;                       \
+                                                                       \
+    for (i = 1; i <= len; i++) {                                       \
+        p = 1000 ^ (len - i);                                          \
+        ver1int += ver1arr[i] * p;                                     \
+        ver2int += ver2arr[i] * p;                                     \
+    }                                                                  \
+                                                                       \
+    if (ver1int < ver2int)                                             \
+        return 2;                                                      \
+    else if (ver1int > ver2int)                                                \
+        return 1;                                                      \
+    else                                                               \
+        return 0;                                                      \
+}' $1 $2`]                                                             
+
+    if test $xmms_got_version -eq 2; then      # failure
+       ifelse([$4], , :, $4)                   
+    else                                       # success!
+       ifelse([$3], , :, $3)
+    fi
+])
+
+AC_DEFUN([AM_PATH_XMMS],
+[
+AC_ARG_WITH(xmms-prefix,[  --with-xmms-prefix=PFX  Prefix where XMMS is installed (optional)],
+       xmms_config_prefix="$withval", xmms_config_prefix="")
+AC_ARG_WITH(xmms-exec-prefix,[  --with-xmms-exec-prefix=PFX Exec prefix where XMMS is installed (optional)],
+       xmms_config_exec_prefix="$withval", xmms_config_exec_prefix="")
+
+if test x$xmms_config_exec_prefix != x; then
+    xmms_config_args="$xmms_config_args --exec-prefix=$xmms_config_exec_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+       XMMS_CONFIG=$xmms_config_exec_prefix/bin/xmms-config
+    fi
+fi
+
+if test x$xmms_config_prefix != x; then
+    xmms_config_args="$xmms_config_args --prefix=$xmms_config_prefix"
+    if test x${XMMS_CONFIG+set} != xset; then
+       XMMS_CONFIG=$xmms_config_prefix/bin/xmms-config
+    fi
+fi
+
+AC_PATH_PROG(XMMS_CONFIG, xmms-config, no)
+min_xmms_version=ifelse([$1], ,0.9.5.1, $1)
+
+if test "$XMMS_CONFIG" = "no"; then
+    no_xmms=yes
+else
+    XMMS_CFLAGS=`$XMMS_CONFIG $xmms_config_args --cflags`
+    XMMS_LIBS=`$XMMS_CONFIG $xmms_config_args --libs`
+    XMMS_VERSION=`$XMMS_CONFIG $xmms_config_args --version`
+    XMMS_DATA_DIR=`$XMMS_CONFIG $xmms_config_args --data-dir`
+    XMMS_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --plugin-dir`
+    XMMS_VISUALIZATION_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args \
+                                       --visualization-plugin-dir`
+    XMMS_INPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --input-plugin-dir`
+    XMMS_OUTPUT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --output-plugin-dir`
+    XMMS_EFFECT_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --effect-plugin-dir`
+    XMMS_GENERAL_PLUGIN_DIR=`$XMMS_CONFIG $xmms_config_args --general-plugin-dir`
+
+    XMMS_TEST_VERSION($XMMS_VERSION, $min_xmms_version, ,no_xmms=version)
+fi
+
+AC_MSG_CHECKING(for XMMS - version >= $min_xmms_version)
+
+if test "x$no_xmms" = x; then
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+else
+    AC_MSG_RESULT(no)
+
+    if test "$XMMS_CONFIG" = "no" ; then
+       echo "*** The xmms-config script installed by XMMS could not be found."
+       echo "*** If XMMS was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the XMMS_CONFIG environment variable to the"
+       echo "*** full path to xmms-config."
+    else
+       if test "$no_xmms" = "version"; then
+           echo "*** An old version of XMMS, $XMMS_VERSION, was found."
+           echo "*** You need a version of XMMS newer than $min_xmms_version."
+           echo "*** The latest version of XMMS is always available from"
+           echo "*** http://www.xmms.org/"
+           echo "***"
+
+            echo "*** If you have already installed a sufficiently new version, this error"
+            echo "*** probably means that the wrong copy of the xmms-config shell script is"
+            echo "*** being found. The easiest way to fix this is to remove the old version"
+            echo "*** of XMMS, but you can also set the XMMS_CONFIG environment to point to the"
+            echo "*** correct copy of xmms-config. (In this case, you will have to"
+            echo "*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf"
+            echo "*** so that the correct libraries are found at run-time)"
+       fi
+    fi
+    XMMS_CFLAGS=""
+    XMMS_LIBS=""
+    ifelse([$3], , :, [$3])
+fi
+AC_SUBST(XMMS_CFLAGS)
+AC_SUBST(XMMS_LIBS)
+AC_SUBST(XMMS_VERSION)
+AC_SUBST(XMMS_DATA_DIR)
+AC_SUBST(XMMS_PLUGIN_DIR)
+AC_SUBST(XMMS_VISUALIZATION_PLUGIN_DIR)
+AC_SUBST(XMMS_INPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_OUTPUT_PLUGIN_DIR)
+AC_SUBST(XMMS_GENERAL_PLUGIN_DIR)
+AC_SUBST(XMMS_EFFECT_PLUGIN_DIR)
+])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644 (file)
index 0000000..607ee5b
--- /dev/null
@@ -0,0 +1,35 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+if FLaC__HAS_DOCBOOK_TO_MAN
+flac.1: flac.sgml
+       docbook-to-man $? > $@ || (docbook2man $? && mv FLAC.1 $@)
+
+metaflac.1: metaflac.sgml
+       docbook-to-man $? > $@ || (docbook2man $? && mv METAFLAC.1 $@)
+else
+flac.1:
+       echo "*** Warning: docbook-to-man not found; man pages will not be built."
+       touch $@
+
+metaflac.1:
+       touch $@
+endif
+
+man_MANS = flac.1 metaflac.1
+
+EXTRA_DIST = $(man_MANS) flac.sgml metaflac.sgml
diff --git a/man/flac.1 b/man/flac.1
new file mode 100644 (file)
index 0000000..fef4ded
--- /dev/null
@@ -0,0 +1,331 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "FLAC" "1" "14 September 2007" "" ""
+
+.SH NAME
+flac \- Free Lossless Audio Codec
+.SH SYNOPSIS
+
+\fBflac\fR [ \fB\fIOPTIONS\fB\fR ] [ \fB\fIinfile.wav\fB\fR | \fB\fIinfile.aiff\fB\fR | \fB\fIinfile.raw\fB\fR | \fB\fIinfile.flac\fB\fR | \fB\fIinfile.oga\fB\fR | \fB\fIinfile.ogg\fB\fR | \fB-\fR\fI ...\fR ]
+
+
+\fBflac\fR [ \fB-d\fR | \fB--decode\fR | \fB-t\fR | \fB--test\fR | \fB-a\fR | \fB--analyze\fR ] [ \fB\fIOPTIONS\fB\fR ] [ \fB\fIinfile.flac\fB\fR | \fB\fIinfile.oga\fB\fR | \fB\fIinfile.ogg\fB\fR | \fB-\fR\fI ...\fR ]
+
+.SH "DESCRIPTION"
+.PP
+\fBflac\fR is a command-line tool for encoding, decoding, testing and analyzing FLAC streams.
+.SH "OPTIONS"
+.PP
+A summary of options is included below.  For a complete
+description, see the HTML documentation.
+.SS "GENERAL OPTIONS"
+.TP
+\fB-v, --version\fR
+Show the flac version number
+.TP
+\fB-h, --help \fR
+Show basic usage and a list of all options
+.TP
+\fB-H, --explain \fR
+Show detailed explanation of usage and all options
+.TP
+\fB-d, --decode \fR
+Decode (the default behavior is to encode)
+.TP
+\fB-t, --test \fR
+Test a flac encoded file (same as -d except no decoded file is written)
+.TP
+\fB-a, --analyze \fR
+Analyze a FLAC encoded file (same as -d except an analysis file is written)
+.TP
+\fB-c, --stdout \fR
+Write output to stdout
+.TP
+\fB-s, --silent \fR
+Silent mode (do not write runtime encode/decode statistics to stderr)
+.TP
+\fB--totally-silent \fR
+Do not print anything of any kind, including warnings or errors.  The exit code will be the only way to determine successful completion.
+.TP
+\fB--no-utf8-convert \fR
+Do not convert tags from local charset to UTF-8.  This is useful for scripts, and setting tags in situations where the locale is wrong.  This option must appear before any tag options!
+.TP
+\fB-w, --warnings-as-errors \fR
+Treat all warnings as errors (which cause flac to terminate with a non-zero exit code).
+.TP
+\fB-f, --force \fR
+Force overwriting of output files.  By default, flac warns that the output file already exists and continues to the next file.
+.TP
+\fB-o \fIfilename\fB, --output-name=\fIfilename\fB\fR
+Force the output file name (usually flac just changes the extension).  May only be used when encoding a single file.  May not be used in conjunction with --output-prefix.
+.TP
+\fB--output-prefix=\fIstring\fB\fR
+Prefix each output file name with the given string.  This can be useful for encoding or decoding files to a different directory.  Make sure if your string is a path name that it ends with a trailing `/' (slash).
+.TP
+\fB--delete-input-file \fR
+Automatically delete the input file after a successful encode or decode.  If there was an error (including a verify error) the input file is left intact.
+.TP
+\fB--keep-foreign-metadata \fR
+If encoding, save WAVE or AIFF non-audio chunks in FLAC metadata.  If decoding, restore any saved non-audio chunks from FLAC metadata when writing the decoded file.  Foreign metadata cannot be transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored when decoding to AIFF.  Input and output must be regular files (not stdin or stdout).
+.TP
+\fB--skip={\fI#\fB|\fImm:ss.ss\fB}\fR
+Skip over the first number of samples of the input.  This works for both encoding and decoding, but not testing.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.
+.TP
+\fB--until={\fI#\fB|[\fI+\fB|\fI-\fB]\fImm:ss.ss\fB}\fR
+Stop at the given sample number for each input file.  This works for both encoding and decoding, but not testing.  The given sample number is not included in the decoded output.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.  If a `+' (plus) sign is at the beginning, the --until point is relative to the --skip point.  If a `-' (minus) sign is at the beginning, the --until point is relative to end of the audio.
+.TP
+\fB--ogg\fR
+When encoding, generate Ogg FLAC output instead of native FLAC.  Ogg FLAC streams are FLAC streams wrapped in an Ogg transport layer.  The resulting file should have an '.oga' extension and will still be decodable by flac.
+
+When decoding, force the input to be treated as Ogg FLAC.  This is useful when piping input from stdin or when the filename does not end in '.oga' or '.ogg'.
+.TP
+\fB--serial-number=\fI#\fB\fR
+When used with --ogg, specifies the serial number to use for the first Ogg FLAC stream, which is then incremented for each additional stream.  When encoding and no serial number is given, flac uses a random number for the first stream, then increments it for each additional stream.  When decoding and no number is given, flac uses the serial number of the first page.
+.SS "ANALYSIS OPTIONS"
+.TP
+\fB--residual-text \fR
+Includes the residual signal in the analysis file.  This will make the file very big, much larger than even the decoded file.
+.TP
+\fB--residual-gnuplot \fR
+Generates a gnuplot file for every subframe; each file will contain the residual distribution of the subframe.  This will create a lot of files.
+.SS "DECODING OPTIONS"
+.TP
+\fB--cue=[\fI#.#\fB][-[\fI#.#\fB]]\fR
+Set the beginning and ending cuepoints to decode.  The optional first #.# is the track and index point at which decoding will start; the default is the beginning of the stream.  The optional second #.# is the track and index point at which decoding will end; the default is the end of the stream.  If the cuepoint does not exist, the closest one before it (for the start point) or after it (for the end point) will be used.  If those don't exist, the start of the stream (for the start point) or end of the stream (for the end point) will be used.  The cuepoints are merely translated into sample numbers then used as --skip and --until.  A CD track can always be cued by, for example, --cue=9.1-10.1 for track 9, even if the CD has no 10th track.
+.TP
+\fB-F, --decode-through-errors \fR
+By default flac stops decoding with an error and removes the partially decoded file if it encounters a bitstream error.  With -F, errors are still printed but flac will continue decoding to completion.  Note that errors may cause the decoded audio to be missing some samples or have silent sections.
+.SS "ENCODING OPTIONS"
+.TP
+\fB-V, --verify\fR
+Verify a correct encoding by decoding the output in parallel and comparing to the original
+.TP
+\fB--lax\fR
+Allow encoder to generate non-Subset files.  The resulting FLAC file may not be streamable or might have trouble being played in all players (especially hardware devices), so you should only use this option in combination with custom encoding options meant for archival.
+.TP
+\fB--replay-gain\fR
+Calculate ReplayGain values and store them as FLAC tags, similar to vorbisgain.  Title gains/peaks will be computed for each input file, and an album gain/peak will be computed for all files.  All input files must have the same resolution, sample rate, and number of channels.  Only mono and stereo files are allowed, and the sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.  Also note that this option may leave a few extra bytes in a PADDING block as the exact size of the tags is not known until all files are processed.  Note that this option cannot be used when encoding to standard output (stdout).
+.TP
+\fB--cuesheet=\fIfilename\fB\fR
+Import the given cuesheet file and store it in a CUESHEET metadata block.  This option may only be used when encoding a single file.  A seekpoint will be added for each index point in the cuesheet to the SEEKTABLE unless --no-cued-seekpoints is specified.
+.TP
+\fB--picture={\fIFILENAME\fB|\fISPECIFICATION\fB}\fR
+Import a picture and store it in a PICTURE metadata block.  More than one --picture command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is
+
+[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE
+
+TYPE is optional; it is a number from one of:
+
+0: Other
+
+1: 32x32 pixels 'file icon' (PNG only)
+
+2: Other file icon
+
+3: Cover (front)
+
+4: Cover (back)
+
+5: Leaflet page
+
+6: Media (e.g. label side of CD)
+
+7: Lead artist/lead performer/soloist
+
+8: Artist/performer
+
+9: Conductor
+
+10: Band/Orchestra
+
+11: Composer
+
+12: Lyricist/text writer
+
+13: Recording Location
+
+14: During recording
+
+15: During performance
+
+16: Movie/video screen capture
+
+17: A bright coloured fish
+
+18: Illustration
+
+19: Band/artist logotype
+
+20: Publisher/Studio logotype
+
+The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.
+
+MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --> to mean that FILE is actually a URL to an image, though this use is discouraged.
+
+DESCRIPTION is optional; the default is an empty string.
+
+The next part specfies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.
+
+FILE is the path to the picture file to be imported, or the URL if MIME type is -->
+
+For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.
+
+The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.
+.TP
+\fB--sector-align\fR
+Align encoding of multiple CD format files on sector boundaries.  See the HTML documentation for more information.
+.TP
+\fB-S {\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}, --seekpoint={\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}\fR
+Include a point or points in a SEEKTABLE.  Using #, a seek point at that sample number is added.  Using X, a placeholder point is added at the end of a the table.  Using #x, # evenly spaced seek points will be added, the first being at sample 0.  Using #s, a seekpoint will be added every # seconds (# does not have to be a whole number; it can be, for example, 9.5, meaning a seekpoint every 9.5 seconds).  You may use many -S options; the resulting SEEKTABLE will be the unique-ified union of all such values.  With no -S options, flac defaults to '-S 10s'.  Use --no-seektable for no SEEKTABLE.  Note: '-S #x' and '-S #s' will not work if the encoder can't determine the input size before starting.  Note: if you use '-S #' and # is >= samples in the input, there will be either no seek point entered (if the input size is determinable before encoding starts) or a placeholder point (if input size is not determinable).
+.TP
+\fB-P \fI#\fB, --padding=\fI#\fB\fR
+Tell the encoder to write a PADDING metadata block of the given length (in bytes) after the STREAMINFO block.  This is useful if you plan to tag the file later with an APPLICATION block; instead of having to rewrite the entire file later just to insert your block, you can write directly over the PADDING block.  Note that the total length of the PADDING block will be 4 bytes longer than the length given because of the 4 metadata block header bytes.  You can force no PADDING block at all to be written with --no-padding.  The encoder writes a PADDING block of 8192 bytes by default (or 65536 bytes if the input audio stream is more that 20 minutes long).
+.TP
+\fB-T \fIFIELD=VALUE\fB, --tag=\fIFIELD=VALUE\fB\fR
+Add a FLAC tag.  The comment must adhere to the Vorbis comment spec; i.e. the FIELD must contain only legal characters, terminated by an 'equals' sign.  Make sure to quote the comment if necessary.  This option may appear more than once to add several comments.  NOTE: all tags will be added to all encoded files.
+.TP
+\fB--tag-from-file=\fIFIELD=FILENAME\fB\fR
+Like --tag, except FILENAME is a file whose contents will be read verbatim to set the tag value.  The contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g.  --tag-from-file="CUESHEET=image.cue").  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.
+.TP
+\fB-b \fI#\fB, --blocksize=\fI#\fB\fR
+Specify the block size in samples.  Subset streams must use one of 192, 576, 1152, 2304, 4608, 256, 512, 1024, 2048, 4096 (and 8192 or 16384 if the sample rate is >48kHz).
+.TP
+\fB-m, --mid-side\fR
+Try mid-side coding for each frame (stereo input only)
+.TP
+\fB-M, --adaptive-mid-side\fR
+Adaptive mid-side coding for all frames (stereo input only)
+.TP
+\fB-0\&..-8, --compression-level-0\&..--compression-level-8\fR
+Fastest compression..highest compression (default is -5).  These are synonyms for other options:
+.RS
+.TP
+\fB-0, --compression-level-0\fR
+Synonymous with -l 0 -b 1152 -r 3
+.TP
+\fB-1, --compression-level-1\fR
+Synonymous with -l 0 -b 1152 -M -r 3
+.TP
+\fB-2, --compression-level-2\fR
+Synonymous with -l 0 -b 1152 -m -r 3
+.TP
+\fB-3, --compression-level-3\fR
+Synonymous with -l 6 -b 4096 -r 4
+.TP
+\fB-4, --compression-level-4\fR
+Synonymous with -l 8 -b 4096 -M -r 4
+.TP
+\fB-5, --compression-level-5\fR
+Synonymous with -l 8 -b 4096 -m -r 5
+.TP
+\fB-6, --compression-level-6\fR
+Synonymous with -l 8 -b 4096 -m -r 6
+.TP
+\fB-7, --compression-level-7\fR
+Synonymous with -l 8 -b 4096 -m -e -r 6
+.TP
+\fB-8, --compression-level-8\fR
+Synonymous with -l 12 -b 4096 -m -e -r 6
+.RE
+.TP
+\fB--fast\fR
+Fastest compression.  Currently synonymous with -0.
+.TP
+\fB--best\fR
+Highest compression.  Currently synonymous with -8.
+.TP
+\fB-e, --exhaustive-model-search\fR
+Do exhaustive model search (expensive!)
+.TP
+\fB-A \fIfunction\fB, --apodization=\fIfunction\fB\fR
+Window audio data with given the apodization function.  The functions are: bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, rectangle, triangle, tukey(P), welch.
+
+For gauss(STDDEV), STDDEV is the standard deviation (0<STDDEV<=0.5).
+
+For tukey(P), P specifies the fraction of the window that is tapered (0<=P<=1; P=0 corresponds to "rectangle" and P=1 corresponds to "hann").
+
+More than one -A option (up to 32) may be used.  Any function that is specified erroneously is silently dropped.  The encoder chooses suitable defaults in the absence of any -A options; any -A option specified replaces the default(s).
+
+When more than one function is specified, then for every subframe the encoder will try each of them separately and choose the window that results in the smallest compressed subframe.  Multiple functions can greatly increase the encoding time.
+.TP
+\fB-l \fI#\fB, --max-lpc-order=\fI#\fB\fR
+Specifies the maximum LPC order. This number must be <= 32. For Subset streams, it must be <=12 if the sample rate is <=48kHz. If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors. Using fixed predictors is faster but usually results in files being 5-10% larger.
+.TP
+\fB-p, --qlp-coeff-precision-search\fR
+Do exhaustive search of LP coefficient quantization (expensive!).  Overrides -q; does nothing if using -l 0
+.TP
+\fB-q \fI#\fB, --qlp-coeff-precision=\fI#\fB\fR
+Precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is 5, default is 0)
+.TP
+\fB-r [\fI#\fB,]\fI#\fB, --rice-partition-order=[\fI#\fB,]\fI#\fB\fR
+Set the [min,]max residual partition order (0..16). min defaults to 0 if unspecified.  Default is -r 5.
+.SS "FORMAT OPTIONS"
+.TP
+\fB--endian={\fIbig\fB|\fIlittle\fB}\fR
+Set the byte order for samples
+.TP
+\fB--channels=\fI#\fB\fR
+Set number of channels.
+.TP
+\fB--bps=\fI#\fB\fR
+Set bits per sample.
+.TP
+\fB--sample-rate=\fI#\fB\fR
+Set sample rate (in Hz).
+.TP
+\fB--sign={\fIsigned\fB|\fIunsigned\fB}\fR
+Set the sign of samples (the default is signed).
+.TP
+\fB--input-size=\fI#\fB\fR
+Specify the size of the raw input in bytes.  If you are encoding raw samples from stdin, you must set this option in order to be able to use --skip, --until, --cue-sheet, or other options that need to know the size of the input beforehand.  If the size given is greater than what is found in the input stream, the encoder will complain about an unexpected end-of-file.  If the size given is less, samples will be truncated.
+.TP
+\fB--force-aiff-format\fR
+Force the decoder to output AIFF format.  This option is not needed if the output filename (as set by -o) ends with \fI\&.aiff\fR\&.  Also, this option has no effect when encoding since input AIFF is auto-detected.
+.TP
+\fB--force-raw-format\fR
+Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in \fI\&.wav\fR).
+.SS "NEGATIVE OPTIONS"
+.TP
+\fB--no-adaptive-mid-side\fR
+.TP
+\fB--no-decode-through-errors\fR
+.TP
+\fB--no-delete-input-file\fR
+.TP
+\fB--no-exhaustive-model-search\fR
+.TP
+\fB--no-lax\fR
+.TP
+\fB--no-mid-side\fR
+.TP
+\fB--no-ogg\fR
+.TP
+\fB--no-padding\fR
+.TP
+\fB--no-qlp-coeff-precision-search\fR
+.TP
+\fB--no-residual-gnuplot\fR
+.TP
+\fB--no-residual-text\fR
+.TP
+\fB--no-sector-align\fR
+.TP
+\fB--no-seektable\fR
+.TP
+\fB--no-silent\fR
+.TP
+\fB--no-verify\fR
+.TP
+\fB--no-warnings-as-errors\fR
+These flags can be used to invert the sense of the corresponding normal option.
+.SH "SEE ALSO"
+.PP
+metaflac(1).
+.PP
+The programs are documented fully by HTML format documentation, available in \fI/usr/share/doc/flac/html\fR on Debian GNU/Linux systems.
+.SH "AUTHOR"
+.PP
+This manual page was written by Matt Zimmerman <mdz@debian.org> for the Debian GNU/Linux system (but may be used by others).
diff --git a/man/flac.sgml b/man/flac.sgml
new file mode 100644 (file)
index 0000000..cd34dfd
--- /dev/null
@@ -0,0 +1,727 @@
+<!doctype refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
+
+  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+  <!ENTITY dhfirstname "<firstname>Matt</firstname>">
+  <!ENTITY dhsurname   "<surname>Zimmerman</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY dhdate      "<date>Nov 4, 2006</date>">
+  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
+  <!ENTITY dhemail     "<email>mdz@debian.org</email>">
+  <!ENTITY dhusername  "Matt Zimmerman">
+  <!ENTITY dhucpackage "<refentrytitle>FLAC</refentrytitle>">
+  <!ENTITY dhpackage   "flac">
+
+  <!ENTITY debian      "<productname>Debian GNU/Linux</productname>">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+]>
+
+<refentry>
+  <docinfo>
+    <address>
+      &dhemail;
+    </address>
+    <author>
+      &dhfirstname;
+      &dhsurname;
+    </author>
+    <copyright>
+      <year>2002,2003,2004,2005</year>
+      <holder>&dhusername;</holder>
+    </copyright>
+    &dhdate;
+  </docinfo>
+  <refmeta>
+    &dhucpackage;
+
+    &dhsection;
+  </refmeta>
+  <refnamediv>
+    <refname>&dhpackage;</refname>
+
+    <refpurpose>Free Lossless Audio Codec</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>flac</command>
+      <arg choice=opt><replaceable>OPTIONS</replaceable></arg>
+      <group rep=repeat>
+       <arg><replaceable>infile.wav</replaceable></arg>
+       <arg><replaceable>infile.aiff</replaceable></arg>
+       <arg><replaceable>infile.raw</replaceable></arg>
+       <arg><replaceable>infile.flac</replaceable></arg>
+       <arg><replaceable>infile.oga</replaceable></arg>
+       <arg><replaceable>infile.ogg</replaceable></arg>
+       <arg>-</arg>
+      </group>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>flac</command>
+      <group>
+       <arg>-d</arg> <arg>--decode</arg>
+       <arg>-t</arg> <arg>--test</arg>
+       <arg>-a</arg> <arg>--analyze</arg>
+      </group>
+      <arg choice=opt><replaceable>OPTIONS</replaceable></arg>
+      <group rep=repeat>
+       <arg><replaceable>infile.flac</replaceable></arg>
+       <arg><replaceable>infile.oga</replaceable></arg>
+       <arg><replaceable>infile.ogg</replaceable></arg>
+       <arg>-</arg>
+      </group>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>flac</command> is a command-line tool for encoding, decoding, testing and analyzing FLAC streams.</para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>A summary of options is included below.  For a complete
+    description, see the HTML documentation.</para>
+
+    <refsect2>
+      <title>General Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>-v</option>, <option>--version</option></term>
+         <listitem>
+           <para>Show the flac version number</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-h</option>, <option>--help</option>
+         </term>
+         <listitem>
+           <para>Show basic usage and a list of all options</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-H</option>, <option>--explain</option>
+         </term>
+         <listitem>
+           <para>Show detailed explanation of usage and all options</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-d</option>, <option>--decode</option>
+         </term>
+         <listitem>
+           <para>Decode (the default behavior is to encode)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-t</option>, <option>--test</option>
+         </term>
+         <listitem>
+           <para>Test a flac encoded file (same as -d except no decoded file is written)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-a</option>, <option>--analyze</option>
+         </term>
+         <listitem>
+           <para>Analyze a FLAC encoded file (same as -d except an analysis file is written)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-c</option>, <option>--stdout</option>
+         </term>
+         <listitem>
+           <para>Write output to stdout</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-s</option>, <option>--silent</option>
+         </term>
+         <listitem>
+           <para>Silent mode (do not write runtime encode/decode statistics to stderr)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--totally-silent</option>
+         </term>
+         <listitem>
+           <para>Do not print anything of any kind, including warnings or errors.  The exit code will be the only way to determine successful completion.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--no-utf8-convert</option>
+         </term>
+         <listitem>
+           <para>Do not convert tags from local charset to UTF-8.  This is useful for scripts, and setting tags in situations where the locale is wrong.  This option must appear before any tag options!</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-w</option>, <option>--warnings-as-errors</option>
+         </term>
+         <listitem>
+           <para>Treat all warnings as errors (which cause flac to terminate with a non-zero exit code).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-f</option>, <option>--force</option>
+         </term>
+         <listitem>
+           <para>Force overwriting of output files.  By default, flac warns that the output file already exists and continues to the next file.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-o</option> <replaceable>filename</replaceable>, <option>--output-name</option>=<replaceable>filename</replaceable></term>
+         <listitem>
+           <para>Force the output file name (usually flac just changes the extension).  May only be used when encoding a single file.  May not be used in conjunction with --output-prefix.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--output-prefix</option>=<replaceable>string</replaceable></term>
+         <listitem>
+           <para>Prefix each output file name with the given string.  This can be useful for encoding or decoding files to a different directory.  Make sure if your string is a path name that it ends with a trailing `/' (slash).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--delete-input-file</option>
+         </term>
+         <listitem>
+           <para>Automatically delete the input file after a successful encode or decode.  If there was an error (including a verify error) the input file is left intact.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--keep-foreign-metadata</option>
+         </term>
+         <listitem>
+           <para>If encoding, save WAVE or AIFF non-audio chunks in FLAC metadata.  If decoding, restore any saved non-audio chunks from FLAC metadata when writing the decoded file.  Foreign metadata cannot be transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored when decoding to AIFF.  Input and output must be regular files (not stdin or stdout).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--skip</option>={<replaceable>#</replaceable>|<replaceable>mm:ss.ss</replaceable>}</term>
+         <listitem>
+           <para>Skip over the first number of samples of the input.  This works for both encoding and decoding, but not testing.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--until</option>={<replaceable>#</replaceable>|[<replaceable>+</replaceable>|<replaceable>-</replaceable>]<replaceable>mm:ss.ss</replaceable>}</term>
+         <listitem>
+           <para>Stop at the given sample number for each input file.  This works for both encoding and decoding, but not testing.  The given sample number is not included in the decoded output.  The alternative form mm:ss.ss can be used to specify minutes, seconds, and fractions of a second.  If a `+' (plus) sign is at the beginning, the --until point is relative to the --skip point.  If a `-' (minus) sign is at the beginning, the --until point is relative to end of the audio.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--ogg</option></term>
+
+         <listitem>
+           <para>When encoding, generate Ogg FLAC output instead of native FLAC.  Ogg FLAC streams are FLAC streams wrapped in an Ogg transport layer.  The resulting file should have an '.oga' extension and will still be decodable by flac.</para>
+           <para>When decoding, force the input to be treated as Ogg FLAC.  This is useful when piping input from stdin or when the filename does not end in '.oga' or '.ogg'.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--serial-number</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>When used with --ogg, specifies the serial number to use for the first Ogg FLAC stream, which is then incremented for each additional stream.  When encoding and no serial number is given, flac uses a random number for the first stream, then increments it for each additional stream.  When decoding and no number is given, flac uses the serial number of the first page.</para>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Analysis Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>--residual-text</option>
+         </term>
+         <listitem>
+           <para>Includes the residual signal in the analysis file.  This will make the file very big, much larger than even the decoded file.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--residual-gnuplot</option>
+         </term>
+         <listitem>
+           <para>Generates a gnuplot file for every subframe; each file will contain the residual distribution of the subframe.  This will create a lot of files.</para>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Decoding Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>--cue=[<replaceable>#.#</replaceable>][-[<replaceable>#.#</replaceable>]]</option></term>
+         <listitem>
+           <para>Set the beginning and ending cuepoints to decode.  The optional first #.# is the track and index point at which decoding will start; the default is the beginning of the stream.  The optional second #.# is the track and index point at which decoding will end; the default is the end of the stream.  If the cuepoint does not exist, the closest one before it (for the start point) or after it (for the end point) will be used.  If those don't exist, the start of the stream (for the start point) or end of the stream (for the end point) will be used.  The cuepoints are merely translated into sample numbers then used as --skip and --until.  A CD track can always be cued by, for example, --cue=9.1-10.1 for track 9, even if the CD has no 10th track.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-F</option>, <option>--decode-through-errors</option>
+         </term>
+         <listitem>
+           <para>By default flac stops decoding with an error and removes the partially decoded file if it encounters a bitstream error.  With -F, errors are still printed but flac will continue decoding to completion.  Note that errors may cause the decoded audio to be missing some samples or have silent sections.</para>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Encoding Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>-V</option>, <option>--verify</option></term>
+
+         <listitem>
+           <para>Verify a correct encoding by decoding the output in parallel and comparing to the original</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--lax</option></term>
+
+         <listitem>
+           <para>Allow encoder to generate non-Subset files.  The resulting FLAC file may not be streamable or might have trouble being played in all players (especially hardware devices), so you should only use this option in combination with custom encoding options meant for archival.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--replay-gain</option></term>
+
+         <listitem>
+           <para>Calculate ReplayGain values and store them as FLAC tags, similar to vorbisgain.  Title gains/peaks will be computed for each input file, and an album gain/peak will be computed for all files.  All input files must have the same resolution, sample rate, and number of channels.  Only mono and stereo files are allowed, and the sample rate must be one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, or 48 kHz.  Also note that this option may leave a few extra bytes in a PADDING block as the exact size of the tags is not known until all files are processed.  Note that this option cannot be used when encoding to standard output (stdout).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--cuesheet</option>=<replaceable>filename</replaceable></term>
+
+         <listitem>
+           <para>Import the given cuesheet file and store it in a CUESHEET metadata block.  This option may only be used when encoding a single file.  A seekpoint will be added for each index point in the cuesheet to the SEEKTABLE unless --no-cued-seekpoints is specified.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--picture</option>={<replaceable>FILENAME</replaceable>|<replaceable>SPECIFICATION</replaceable>}</term>
+
+         <listitem>
+           <para>Import a picture and store it in a PICTURE metadata block.  More than one --picture command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is</para>
+           <para>[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE</para>
+           <para>TYPE is optional; it is a number from one of:</para>
+           <para>0: Other</para>
+           <para>1: 32x32 pixels 'file icon' (PNG only)</para>
+           <para>2: Other file icon</para>
+           <para>3: Cover (front)</para>
+           <para>4: Cover (back)</para>
+           <para>5: Leaflet page</para>
+           <para>6: Media (e.g. label side of CD)</para>
+           <para>7: Lead artist/lead performer/soloist</para>
+           <para>8: Artist/performer</para>
+           <para>9: Conductor</para>
+           <para>10: Band/Orchestra</para>
+           <para>11: Composer</para>
+           <para>12: Lyricist/text writer</para>
+           <para>13: Recording Location</para>
+           <para>14: During recording</para>
+           <para>15: During performance</para>
+           <para>16: Movie/video screen capture</para>
+           <para>17: A bright coloured fish</para>
+           <para>18: Illustration</para>
+           <para>19: Band/artist logotype</para>
+           <para>20: Publisher/Studio logotype</para>
+           <para>The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.</para>
+
+           <para>MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --&gt; to mean that FILE is actually a URL to an image, though this use is discouraged.</para>
+
+           <para>DESCRIPTION is optional; the default is an empty string.</para>
+
+           <para>The next part specfies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.</para>
+
+           <para>FILE is the path to the picture file to be imported, or the URL if MIME type is --&gt;</para>
+
+           <para>For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.</para>
+
+           <para>The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--sector-align</option></term>
+
+         <listitem>
+           <para>Align encoding of multiple CD format files on sector boundaries.  See the HTML documentation for more information.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-S</option> {<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}, <option>--seekpoint</option>={<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}</term>
+
+         <listitem>
+           <para>Include a point or points in a SEEKTABLE.  Using #, a seek point at that sample number is added.  Using X, a placeholder point is added at the end of a the table.  Using #x, # evenly spaced seek points will be added, the first being at sample 0.  Using #s, a seekpoint will be added every # seconds (# does not have to be a whole number; it can be, for example, 9.5, meaning a seekpoint every 9.5 seconds).  You may use many -S options; the resulting SEEKTABLE will be the unique-ified union of all such values.  With no -S options, flac defaults to '-S 10s'.  Use --no-seektable for no SEEKTABLE.  Note: '-S #x' and '-S #s' will not work if the encoder can't determine the input size before starting.  Note: if you use '-S #' and # is >= samples in the input, there will be either no seek point entered (if the input size is determinable before encoding starts) or a placeholder point (if input size is not determinable).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-P</option> <replaceable>#</replaceable>, <option>--padding</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Tell the encoder to write a PADDING metadata block of the given length (in bytes) after the STREAMINFO block.  This is useful if you plan to tag the file later with an APPLICATION block; instead of having to rewrite the entire file later just to insert your block, you can write directly over the PADDING block.  Note that the total length of the PADDING block will be 4 bytes longer than the length given because of the 4 metadata block header bytes.  You can force no PADDING block at all to be written with --no-padding.  The encoder writes a PADDING block of 8192 bytes by default (or 65536 bytes if the input audio stream is more that 20 minutes long).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-T</option> <replaceable>FIELD=VALUE</replaceable>, <option>--tag</option>=<replaceable>FIELD=VALUE</replaceable></term>
+
+         <listitem>
+           <para>Add a FLAC tag.  The comment must adhere to the Vorbis comment spec; i.e. the FIELD must contain only legal characters, terminated by an 'equals' sign.  Make sure to quote the comment if necessary.  This option may appear more than once to add several comments.  NOTE: all tags will be added to all encoded files.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--tag-from-file</option>=<replaceable>FIELD=FILENAME</replaceable></term>
+
+         <listitem>
+           <para>Like --tag, except FILENAME is a file whose contents will be read verbatim to set the tag value.  The contents will be converted to UTF-8 from the local charset.  This can be used to store a cuesheet in a tag (e.g.  --tag-from-file="CUESHEET=image.cue").  Do not try to store binary data in tag fields!  Use APPLICATION blocks for that.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-b</option> <replaceable>#</replaceable>, <option>--blocksize</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Specify the block size in samples.  Subset streams must use one of 192, 576, 1152, 2304, 4608, 256, 512, 1024, 2048, 4096 (and 8192 or 16384 if the sample rate is &gt;48kHz).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-m</option>, <option>--mid-side</option></term>
+
+         <listitem>
+           <para>Try mid-side coding for each frame (stereo input only)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-M</option>, <option>--adaptive-mid-side</option></term>
+
+         <listitem>
+           <para>Adaptive mid-side coding for all frames (stereo input only)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-0</option>..<option>-8</option>, <option>--compression-level-0</option>..<option>--compression-level-8</option></term>
+
+         <listitem>
+           <para>Fastest compression..highest compression (default is -5).  These are synonyms for other options:</para>
+
+           <variablelist>
+             <varlistentry>
+               <term><option>-0</option>, <option>--compression-level-0</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 0 -b 1152 -r 3</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-1</option>, <option>--compression-level-1</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 0 -b 1152 -M -r 3</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-2</option>, <option>--compression-level-2</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 0 -b 1152 -m -r 3</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-3</option>, <option>--compression-level-3</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 6 -b 4096 -r 4</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-4</option>, <option>--compression-level-4</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 8 -b 4096 -M -r 4</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-5</option>, <option>--compression-level-5</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 8 -b 4096 -m -r 5</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-6</option>, <option>--compression-level-6</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 8 -b 4096 -m -r 6</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-7</option>, <option>--compression-level-7</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 8 -b 4096 -m -e -r 6</para>
+               </listitem>
+             </varlistentry>
+
+             <varlistentry>
+               <term><option>-8</option>, <option>--compression-level-8</option></term>
+
+               <listitem>
+                 <para>Synonymous with -l 12 -b 4096 -m -e -r 6</para>
+               </listitem>
+             </varlistentry>
+           </variablelist>
+
+         </listitem>
+
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--fast</option></term>
+
+         <listitem>
+           <para>Fastest compression.  Currently synonymous with -0.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--best</option></term>
+
+         <listitem>
+           <para>Highest compression.  Currently synonymous with -8.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-e</option>, <option>--exhaustive-model-search</option></term>
+
+         <listitem>
+           <para>Do exhaustive model search (expensive!)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-A</option> <replaceable>function</replaceable>, <option>--apodization</option>=<replaceable>function</replaceable></term>
+
+         <listitem>
+           <para>Window audio data with given the apodization function.  The functions are: bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, rectangle, triangle, tukey(P), welch.</para>
+           <para>For gauss(STDDEV), STDDEV is the standard deviation (0&lt;STDDEV&lt;=0.5).</para>
+           <para>For tukey(P), P specifies the fraction of the window that is tapered (0&lt;=P&lt;=1; P=0 corresponds to "rectangle" and P=1 corresponds to "hann").</para>
+           <para>More than one -A option (up to 32) may be used.  Any function that is specified erroneously is silently dropped.  The encoder chooses suitable defaults in the absence of any -A options; any -A option specified replaces the default(s).</para>
+           <para>When more than one function is specified, then for every subframe the encoder will try each of them separately and choose the window that results in the smallest compressed subframe.  Multiple functions can greatly increase the encoding time.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-l</option> <replaceable>#</replaceable>, <option>--max-lpc-order</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Specifies the maximum LPC order. This number must be &lt;= 32. For Subset streams, it must be &lt;=12 if the sample rate is &lt;=48kHz. If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors. Using fixed predictors is faster but usually results in files being 5-10% larger.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-p</option>, <option>--qlp-coeff-precision-search</option></term>
+
+         <listitem>
+           <para>Do exhaustive search of LP coefficient quantization (expensive!).  Overrides -q; does nothing if using -l 0</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-q</option> <replaceable>#</replaceable>, <option>--qlp-coeff-precision</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is 5, default is 0)</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>-r</option> [<replaceable>#</replaceable>,]<replaceable>#</replaceable>, <option>--rice-partition-order</option>=[<replaceable>#</replaceable>,]<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Set the [min,]max residual partition order (0..16). min defaults to 0 if unspecified.  Default is -r 5.</para>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+
+    </refsect2>
+    <refsect2>
+      <title>Format Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>--endian</option>={<replaceable>big</replaceable>|<replaceable>little</replaceable>}</term>
+
+         <listitem>
+           <para>Set the byte order for samples</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--channels</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Set number of channels.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--bps</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Set bits per sample.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--sample-rate</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Set sample rate (in Hz).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--sign</option>={<replaceable>signed</replaceable>|<replaceable>unsigned</replaceable>}</term>
+
+         <listitem>
+           <para>Set the sign of samples (the default is signed).</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--input-size</option>=<replaceable>#</replaceable></term>
+
+         <listitem>
+           <para>Specify the size of the raw input in bytes.  If you are encoding raw samples from stdin, you must set this option in order to be able to use --skip, --until, --cue-sheet, or other options that need to know the size of the input beforehand.  If the size given is greater than what is found in the input stream, the encoder will complain about an unexpected end-of-file.  If the size given is less, samples will be truncated.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--force-aiff-format</option></term>
+
+         <listitem>
+           <para>Force the decoder to output AIFF format.  This option is not needed if the output filename (as set by -o) ends with <filename>.aiff</filename>.  Also, this option has no effect when encoding since input AIFF is auto-detected.</para>
+         </listitem>
+       </varlistentry>
+
+       <varlistentry>
+         <term><option>--force-raw-format</option></term>
+
+         <listitem>
+           <para>Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in <filename>.wav</filename>).</para>
+         </listitem>
+       </varlistentry>
+
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Negative Options</title>
+
+      <variablelist>
+       <varlistentry>
+         <term><option>--no-adaptive-mid-side</option></term>
+         <term><option>--no-decode-through-errors</option></term>
+         <term><option>--no-delete-input-file</option></term>
+         <term><option>--no-exhaustive-model-search</option></term>
+         <term><option>--no-lax</option></term>
+         <term><option>--no-mid-side</option></term>
+         <term><option>--no-ogg</option></term>
+         <term><option>--no-padding</option></term>
+         <term><option>--no-qlp-coeff-precision-search</option></term>
+         <term><option>--no-residual-gnuplot</option></term>
+         <term><option>--no-residual-text</option></term>
+         <term><option>--no-sector-align</option></term>
+         <term><option>--no-seektable</option></term>
+         <term><option>--no-silent</option></term>
+         <term><option>--no-verify</option></term>
+         <term><option>--no-warnings-as-errors</option></term>
+         <listitem>
+           <para>These flags can be used to invert the sense of the corresponding normal option.</para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+
+    </refsect2>
+
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>metaflac(1).</para>
+
+    <para>The programs are documented fully by HTML format documentation, available in <filename>/usr/share/doc/flac/html</filename> on &debian; systems.</para>
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+
+    <para>This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others).</para>
+
+    <!-- <para>Permission is granted to copy, distribute and/or modify this document under the terms of the <acronym>GNU</acronym> Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.  A copy of the license can be found under <filename>/usr/share/common-licenses/FDL</filename>.</para> -->
+
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+      Local variables:
+      mode: sgml
+      sgml-omittag:t
+      sgml-shorttag:t
+      sgml-minimize-attributes:nil
+      sgml-always-quote-attributes:t
+      sgml-indent-step:2
+      sgml-indent-data:t
+      sgml-parent-document:nil
+      sgml-default-dtd-file:nil
+      sgml-exposed-tags:nil
+      sgml-local-catalogs:nil
+      sgml-local-ecat-files:nil
+      End:
+      -->
diff --git a/man/metaflac.1 b/man/metaflac.1
new file mode 100644 (file)
index 0000000..9cc593d
--- /dev/null
@@ -0,0 +1,299 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "METAFLAC" "1" "14 September 2007" "" ""
+
+.SH NAME
+metaflac \- program to list, add, remove, or edit metadata in one or more FLAC files.
+.SH SYNOPSIS
+
+\fBmetaflac\fR [ \fB\fIoptions\fB\fR ] [ \fB\fIoperations\fB\fR ] \fB\fIFLACfile\fB\fR\fI ...\fR
+
+.SH "DESCRIPTION"
+.PP
+Use \fBmetaflac\fR to list, add, remove, or edit
+metadata in one or more FLAC files.  You may perform one major operation,
+or many shorthand operations at a time.
+.SH "OPTIONS"
+.TP
+\fB--preserve-modtime\fR
+Preserve the original modification time in spite of edits.
+.TP
+\fB--with-filename\fR
+Prefix each output line with the FLAC file name (the default if
+more than one FLAC file is specified).
+.TP
+\fB--no-filename\fR
+Do not prefix each output line with the FLAC file name (the default
+if only one FLAC file is specified).
+.TP
+\fB--no-utf8-convert\fR
+Do not convert tags from UTF-8 to local charset, or vice versa. This is
+useful for scripts, and setting tags in situations where the locale is wrong.
+.TP
+\fB--dont-use-padding\fR
+By default metaflac tries to use padding where possible to avoid
+rewriting the entire file if the metadata size changes.  Use this
+option to tell metaflac to not take advantage of padding this way.
+.SH "SHORTHAND OPERATIONS"
+.TP
+\fB--show-md5sum\fR
+Show the MD5 signature from the STREAMINFO block.
+.TP
+\fB--show-min-blocksize\fR
+Show the minimum block size from the STREAMINFO block.
+.TP
+\fB--show-max-blocksize\fR
+Show the maximum block size from the STREAMINFO block.
+.TP
+\fB--show-min-framesize\fR
+Show the minimum frame size from the STREAMINFO block.
+.TP
+\fB--show-max-framesize\fR
+Show the maximum frame size from the STREAMINFO block.
+.TP
+\fB--show-sample-rate\fR
+Show the sample rate from the STREAMINFO block.
+.TP
+\fB--show-channels\fR
+Show the number of channels from the STREAMINFO block.
+.TP
+\fB--show-bps\fR
+Show the # of bits per sample from the STREAMINFO block.
+.TP
+\fB--show-total-samples\fR
+Show the total # of samples from the STREAMINFO block.
+.TP
+\fB--show-vendor-tag\fR
+Show the vendor string from the VORBIS_COMMENT block.
+.TP
+\fB--show-tag=name\fR
+Show all tags where the the field name matches 'name'.
+.TP
+\fB--remove-tag=name\fR
+Remove all tags whose field name is 'name'.
+.TP
+\fB--remove-first-tag=name\fR
+Remove first tag whose field name is 'name'.
+.TP
+\fB--remove-all-tags\fR
+Remove all tags, leaving only the vendor string.
+.TP
+\fB--set-tag=field\fR
+Add a tag.  The field must comply with the
+Vorbis comment spec, of the form "NAME=VALUE".  If there is
+currently no tag block, one will be created.
+.TP
+\fB--set-tag-from-file=field\fR
+Like --set-tag, except the VALUE is a filename whose
+contents will be read verbatim to set the tag value.
+Unless --no-utf8-convert is specified, the contents will be
+converted to UTF-8 from the local charset.  This can be used
+to store a cuesheet in a tag (e.g.
+--set-tag-from-file="CUESHEET=image.cue").  Do not try to
+store binary data in tag fields!  Use APPLICATION blocks for
+that.
+.TP
+\fB--import-tags-from=file\fR
+Import tags from a file.  Use '-' for stdin.  Each
+line should be of the form NAME=VALUE.  Multi-line comments
+are currently not supported.  Specify --remove-all-tags and/or
+--no-utf8-convert before --import-tags-from if necessary.  If
+FILE is '-' (stdin), only one FLAC file may be specified.
+.TP
+\fB--export-tags-to=file\fR
+Export tags to a file.  Use '-' for stdout.  Each
+line will be of the form NAME=VALUE.  Specify
+--no-utf8-convert if necessary.
+.TP
+\fB--import-cuesheet-from=file\fR
+Import a cuesheet from a file.  Use '-' for stdin.  Only one
+FLAC file may be specified.  A seekpoint will be added for each
+index point in the cuesheet to the SEEKTABLE unless
+--no-cued-seekpoints is specified.
+.TP
+\fB--export-cuesheet-to=file\fR
+Export CUESHEET block to a cuesheet file, suitable for use by
+CD authoring software.  Use '-' for stdout.  Only one FLAC file
+may be specified on the command line.
+.TP
+\fB--import-picture-from={\fIFILENAME\fB|\fISPECIFICATION\fB}\fR
+Import a picture and store it in a PICTURE metadata block.  More than one --import-picture-from command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is
+
+[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE
+
+TYPE is optional; it is a number from one of:
+
+0: Other
+
+1: 32x32 pixels 'file icon' (PNG only)
+
+2: Other file icon
+
+3: Cover (front)
+
+4: Cover (back)
+
+5: Leaflet page
+
+6: Media (e.g. label side of CD)
+
+7: Lead artist/lead performer/soloist
+
+8: Artist/performer
+
+9: Conductor
+
+10: Band/Orchestra
+
+11: Composer
+
+12: Lyricist/text writer
+
+13: Recording Location
+
+14: During recording
+
+15: During performance
+
+16: Movie/video screen capture
+
+17: A bright coloured fish
+
+18: Illustration
+
+19: Band/artist logotype
+
+20: Publisher/Studio logotype
+
+The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.
+
+MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --> to mean that FILE is actually a URL to an image, though this use is discouraged.
+
+DESCRIPTION is optional; the default is an empty string.
+
+The next part specfies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.
+
+FILE is the path to the picture file to be imported, or the URL if MIME type is -->
+
+For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.
+
+The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.
+.TP
+\fB--export-picture-to=file\fR
+Export PICTURE block to a file.  Use '-' for stdout.  Only one FLAC file may be specified on the command line.  The first PICTURE block will be exported unless --export-picture-to is preceded by a --block-number=# option to specify the exact metadata block to extract.  Note that the block number is the one shown by --list.
+.TP
+\fB--add-replay-gain\fR
+Calculates the title and album gains/peaks of the given FLAC
+files as if all the files were part of one album, then stores
+them as FLAC tags.  The tags are the same as
+those used by vorbisgain.  Existing ReplayGain tags will be
+replaced.  If only one FLAC file is given, the album and title
+gains will be the same.  Since this operation requires two
+passes, it is always executed last, after all other operations
+have been completed and written to disk.  All FLAC files
+specified must have the same resolution, sample rate, and
+number of channels.  The sample rate must be one of 8, 11.025,
+12, 16, 22.05, 24, 32, 44.1, or 48 kHz.
+.TP
+\fB--remove-replay-gain\fR
+Removes the ReplayGain tags.
+.TP
+\fB--add-seekpoint={\fI#\fB|\fIX\fB|\fI#x\fB|\fI#s\fB}\fR
+Add seek points to a SEEKTABLE block.  Using #, a seek point at
+that sample number is added.  Using X, a placeholder point is
+added at the end of a the table.  Using #x, # evenly spaced seek
+points will be added, the first being at sample 0.  Using #s, a
+seekpoint will be added every # seconds (# does not have to be a
+whole number; it can be, for example, 9.5, meaning a seekpoint
+every 9.5 seconds).  If no SEEKTABLE block exists, one will be
+created.  If one already exists, points will be added to the
+existing table, and any duplicates will be turned into placeholder
+points.  You may use many --add-seekpoint options; the resulting
+SEEKTABLE will be the unique-ified union of all such values.
+Example: --add-seekpoint=100x --add-seekpoint=3.5s will add 100
+evenly spaced seekpoints and a seekpoint every 3.5 seconds.
+.TP
+\fB--add-padding=length\fR
+Add a padding block of the given length (in bytes).  The overall
+length of the new block will be 4 + length; the extra 4 bytes is
+for the metadata block header.
+.SH "MAJOR OPERATIONS"
+.TP
+\fB--list\fR
+List the contents of one or more metadata blocks to stdout.  By
+default, all metadata blocks are listed in text format.  Use the
+following options to change this behavior:
+.RS
+.TP
+\fB--block-number=#[,#[...]]\fR
+An optional comma-separated list of block numbers to display.
+The first block, the STREAMINFO block, is block 0.
+.TP
+\fB--block-type=type[,type[...]]\fR
+.TP
+\fB--except-block-type=type[,type[...]]\fR
+An optional comma-separated list of block types to be included
+or ignored with this option.  Use only one of --block-type or
+--except-block-type.  The valid block types are: STREAMINFO,
+PADDING, APPLICATION, SEEKTABLE, VORBIS_COMMENT.  You may
+narrow down the types of APPLICATION blocks displayed as
+follows:
+
+APPLICATION:abcd        The APPLICATION block(s) whose textual repre-
+sentation of the 4-byte ID is "abcd"
+APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-
+endian representation of the 4-byte ID is
+"0xXXXXXXXX".  For the example "abcd" above the
+hexadecimal equivalalent is 0x61626364
+.sp
+.RS
+.B "Note:"
+if both --block-number and --[except-]block-type are
+specified, the result is the logical AND of both
+arguments.
+.RE
+.TP
+\fB--application-data-format=hexdump|text\fR
+If the application block you are displaying contains binary
+data but your --data-format=text, you can display a hex dump
+of the application data contents instead using
+--application-data-format=hexdump.
+.RE
+.TP
+\fB--remove\fR
+Remove one or more metadata blocks from the metadata.  Unless
+--dont-use-padding is specified, the blocks will be replaced with
+padding.  You may not remove the STREAMINFO block.
+.RS
+.TP
+\fB--block-number=#[,#[...]]\fR
+.TP
+\fB--block-type=type[,type[...]]\fR
+.TP
+\fB--except-block-type=type[,type[...]]\fR
+See --list above for usage.
+.sp
+.RS
+.B "Note:"
+if both --block-number and --[except-]block-type are
+specified, the result is the logical AND of both arguments.
+.RE
+.RE
+.TP
+\fB--remove-all\fR
+Remove all metadata blocks (except the STREAMINFO block) from the
+metadata.  Unless --dont-use-padding is specified, the blocks will
+be replaced with padding.
+.TP
+\fB--merge-padding\fR
+Merge adjacent PADDING blocks into single blocks.
+.TP
+\fB--sort-padding\fR
+Move all PADDING blocks to the end of the metadata and merge them
+into a single block.
+.SH "SEE ALSO"
+.PP
+flac(1).
diff --git a/man/metaflac.sgml b/man/metaflac.sgml
new file mode 100644 (file)
index 0000000..bb9fc8a
--- /dev/null
@@ -0,0 +1,570 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- Process this file with docbook-to-man to generate an nroff manual
+     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
+     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
+     less'.  A typical entry in a Makefile or Makefile.am is:
+
+manpage.1: manpage.sgml
+       docbook-to-man $< > $@
+  -->
+
+<!-- This is based on an example constructed by Colin Watson
+     <email>cjwatson@debian.org</email>, based on a man page template
+     provided by Tom Christiansen <email>tchrist@jhereg.perl.com</email>
+     and a DocBook man page example by Craig Small
+     <email>csmall@debian.org</email>.
+  -->
+
+  <!-- Fill in the various UPPER CASE things here. -->
+  <!ENTITY manfirstname "<firstname>dann</firstname>">
+  <!ENTITY mansurname   "<surname>frazier</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY mandate      "<date>2006-11-14</date>">
+  <!-- SECTION should be 1-8, maybe with subsection. Other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY mansection   "<manvolnum>1</manvolnum>">
+  <!ENTITY manemail     "<email>dannf@debian.org</email>">
+  <!ENTITY manusername  "dannf">
+  <!ENTITY manucpackage "<refentrytitle>METAFLAC</refentrytitle>">
+  <!ENTITY manpackage   "metaflac">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      &manemail;
+    </address>
+    <author>
+      &manfirstname;
+      &mansurname;
+    </author>
+    <copyright>
+      <year>2002,2003,2004,2005</year>
+      <holder>&manusername;</holder>
+    </copyright>
+    &mandate;
+  </refentryinfo>
+  <refmeta>
+    &manucpackage;
+
+    &mansection;
+  </refmeta>
+  <refnamediv>
+    <refname>&manpackage;</refname>
+
+    <refpurpose>
+      program to list, add, remove, or edit metadata in one or more FLAC files.
+    </refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&manpackage;</command>
+
+      <group choice="opt"><arg><replaceable>options</replaceable></arg></group>
+      <group choice="opt">
+       <arg><replaceable>operations</replaceable></arg></group>
+      <arg rep="repeat" choice="req"><replaceable>FLACfile</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>Use <command>&manpackage;</command> to list, add, remove, or edit
+      metadata in one or more FLAC files.  You may perform one major operation,
+      or many shorthand operations at a time.</para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--preserve-modtime</option></term>
+        <listitem>
+          <para>
+           Preserve the original modification time in spite of edits.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--with-filename</option></term>
+        <listitem>
+          <para>
+           Prefix each output line with the FLAC file name (the default if
+           more than one FLAC file is specified).
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--no-filename</option></term>
+        <listitem>
+          <para>
+           Do not prefix each output line with the FLAC file name (the default
+           if only one FLAC file is specified).
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--no-utf8-convert</option></term>
+        <listitem>
+          <para>
+           Do not convert tags from UTF-8 to local charset, or vice versa. This is
+           useful for scripts, and setting tags in situations where the locale is wrong.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--dont-use-padding</option></term>
+        <listitem>
+          <para>
+           By default metaflac tries to use padding where possible to avoid
+           rewriting the entire file if the metadata size changes.  Use this
+           option to tell metaflac to not take advantage of padding this way.
+         </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>SHORTHAND OPERATIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--show-md5sum</option></term>
+        <listitem>
+          <para>
+           Show the MD5 signature from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-min-blocksize</option></term>
+        <listitem>
+          <para>
+           Show the minimum block size from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-max-blocksize</option></term>
+        <listitem>
+          <para>
+           Show the maximum block size from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-min-framesize</option></term>
+        <listitem>
+          <para>
+           Show the minimum frame size from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-max-framesize</option></term>
+        <listitem>
+          <para>
+           Show the maximum frame size from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-sample-rate</option></term>
+        <listitem>
+          <para>
+           Show the sample rate from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-channels</option></term>
+        <listitem>
+          <para>
+           Show the number of channels from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-bps</option></term>
+        <listitem>
+          <para>
+           Show the # of bits per sample from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-total-samples</option></term>
+        <listitem>
+          <para>
+           Show the total # of samples from the STREAMINFO block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-vendor-tag</option></term>
+        <listitem>
+          <para>
+           Show the vendor string from the VORBIS_COMMENT block.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--show-tag=name</option></term>
+        <listitem>
+          <para>
+           Show all tags where the the field name matches 'name'.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-tag=name</option></term>
+        <listitem>
+          <para>
+           Remove all tags whose field name is 'name'.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-first-tag=name</option></term>
+        <listitem>
+          <para>
+           Remove first tag whose field name is 'name'.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-all-tags</option></term>
+        <listitem>
+          <para>
+           Remove all tags, leaving only the vendor string.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--set-tag=field</option></term>
+        <listitem>
+          <para>
+           Add a tag.  The field must comply with the
+           Vorbis comment spec, of the form "NAME=VALUE".  If there is
+           currently no tag block, one will be created.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--set-tag-from-file=field</option></term>
+        <listitem>
+          <para>
+           Like --set-tag, except the VALUE is a filename whose
+           contents will be read verbatim to set the tag value.
+           Unless --no-utf8-convert is specified, the contents will be
+           converted to UTF-8 from the local charset.  This can be used
+           to store a cuesheet in a tag (e.g.
+           --set-tag-from-file="CUESHEET=image.cue").  Do not try to
+           store binary data in tag fields!  Use APPLICATION blocks for
+           that.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--import-tags-from=file</option></term>
+        <listitem>
+         <para>
+           Import tags from a file.  Use '-' for stdin.  Each
+           line should be of the form NAME=VALUE.  Multi-line comments
+           are currently not supported.  Specify --remove-all-tags and/or
+           --no-utf8-convert before --import-tags-from if necessary.  If
+           FILE is '-' (stdin), only one FLAC file may be specified.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--export-tags-to=file</option></term>
+        <listitem>
+         <para>
+           Export tags to a file.  Use '-' for stdout.  Each
+           line will be of the form NAME=VALUE.  Specify
+           --no-utf8-convert if necessary.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--import-cuesheet-from=file</option></term>
+        <listitem>
+         <para>
+           Import a cuesheet from a file.  Use '-' for stdin.  Only one
+           FLAC file may be specified.  A seekpoint will be added for each
+           index point in the cuesheet to the SEEKTABLE unless
+           --no-cued-seekpoints is specified.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--export-cuesheet-to=file</option></term>
+        <listitem>
+         <para>
+           Export CUESHEET block to a cuesheet file, suitable for use by
+           CD authoring software.  Use '-' for stdout.  Only one FLAC file
+           may be specified on the command line.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--import-picture-from</option>={<replaceable>FILENAME</replaceable>|<replaceable>SPECIFICATION</replaceable>}</term>
+       <listitem>
+         <para>Import a picture and store it in a PICTURE metadata block.  More than one --import-picture-from command can be specified.  Either a filename for the picture file or a more complete specification form can be used.  The SPECIFICATION is a string whose parts are separated by | (pipe) characters.  Some parts may be left empty to invoke default values.  FILENAME is just shorthand for "||||FILENAME".  The format of SPECIFICATION is</para>
+         <para>[TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE</para>
+         <para>TYPE is optional; it is a number from one of:</para>
+         <para>0: Other</para>
+         <para>1: 32x32 pixels 'file icon' (PNG only)</para>
+         <para>2: Other file icon</para>
+         <para>3: Cover (front)</para>
+         <para>4: Cover (back)</para>
+         <para>5: Leaflet page</para>
+         <para>6: Media (e.g. label side of CD)</para>
+         <para>7: Lead artist/lead performer/soloist</para>
+         <para>8: Artist/performer</para>
+         <para>9: Conductor</para>
+         <para>10: Band/Orchestra</para>
+         <para>11: Composer</para>
+         <para>12: Lyricist/text writer</para>
+         <para>13: Recording Location</para>
+         <para>14: During recording</para>
+         <para>15: During performance</para>
+         <para>16: Movie/video screen capture</para>
+         <para>17: A bright coloured fish</para>
+         <para>18: Illustration</para>
+         <para>19: Band/artist logotype</para>
+         <para>20: Publisher/Studio logotype</para>
+         <para>The default is 3 (front cover).  There may only be one picture each of type 1 and 2 in a file.</para>
+
+         <para>MIME-TYPE is optional; if left blank, it will be detected from the file.  For best compatibility with players, use pictures with MIME type image/jpeg or image/png.  The MIME type can also be --&gt; to mean that FILE is actually a URL to an image, though this use is discouraged.</para>
+
+         <para>DESCRIPTION is optional; the default is an empty string.</para>
+
+         <para>The next part specfies the resolution and color information.  If the MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave this empty and they can be detected from the file.  Otherwise, you must specify the width in pixels, height in pixels, and color depth in bits-per-pixel.  If the image has indexed colors you should also specify the number of colors used.  When manually specified, it is not checked against the file for accuracy.</para>
+
+         <para>FILE is the path to the picture file to be imported, or the URL if MIME type is --&gt;</para>
+
+         <para>For example, "|image/jpeg|||../cover.jpg" will embed the JPEG file at ../cover.jpg, defaulting to type 3 (front cover) and an empty description.  The resolution and color info will be retrieved from the file itself.</para>
+
+         <para>The specification "4|-->|CD|320x300x24/173|http://blah.blah/backcover.tiff" will embed the given URL, with type 4 (back cover), description "CD", and a manually specified resolution of 320x300, 24 bits-per-pixel, and 173 colors.  The file at the URL will not be fetched; the URL itself is stored in the PICTURE metadata block.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--export-picture-to=file</option></term>
+        <listitem>
+         <para>
+           Export PICTURE block to a file.  Use '-' for stdout.  Only one FLAC file may be specified on the command line.  The first PICTURE block will be exported unless --export-picture-to is preceded by a --block-number=# option to specify the exact metadata block to extract.  Note that the block number is the one shown by --list.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--add-replay-gain</option></term>
+        <listitem>
+         <para>
+           Calculates the title and album gains/peaks of the given FLAC
+           files as if all the files were part of one album, then stores
+           them as FLAC tags.  The tags are the same as
+           those used by vorbisgain.  Existing ReplayGain tags will be
+           replaced.  If only one FLAC file is given, the album and title
+           gains will be the same.  Since this operation requires two
+           passes, it is always executed last, after all other operations
+           have been completed and written to disk.  All FLAC files
+           specified must have the same resolution, sample rate, and
+           number of channels.  The sample rate must be one of 8, 11.025,
+           12, 16, 22.05, 24, 32, 44.1, or 48 kHz.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--remove-replay-gain</option></term>
+        <listitem>
+         <para>
+           Removes the ReplayGain tags.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>--add-seekpoint</option>={<replaceable>#</replaceable>|<replaceable>X</replaceable>|<replaceable>#x</replaceable>|<replaceable>#s</replaceable>}</term>
+       <listitem>
+         <para>
+           Add seek points to a SEEKTABLE block.  Using #, a seek point at
+           that sample number is added.  Using X, a placeholder point is
+           added at the end of a the table.  Using #x, # evenly spaced seek
+           points will be added, the first being at sample 0.  Using #s, a
+           seekpoint will be added every # seconds (# does not have to be a
+           whole number; it can be, for example, 9.5, meaning a seekpoint
+           every 9.5 seconds).  If no SEEKTABLE block exists, one will be
+           created.  If one already exists, points will be added to the
+           existing table, and any duplicates will be turned into placeholder
+           points.  You may use many --add-seekpoint options; the resulting
+           SEEKTABLE will be the unique-ified union of all such values.
+           Example: --add-seekpoint=100x --add-seekpoint=3.5s will add 100
+           evenly spaced seekpoints and a seekpoint every 3.5 seconds.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--add-padding=length</option></term>
+        <listitem>
+          <para>
+           Add a padding block of the given length (in bytes).  The overall
+           length of the new block will be 4 + length; the extra 4 bytes is
+           for the metadata block header.
+         </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>MAJOR OPERATIONS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>--list</option></term>
+        <listitem>
+          <para>
+           List the contents of one or more metadata blocks to stdout.  By
+           default, all metadata blocks are listed in text format.  Use the
+           following options to change this behavior:
+         </para>
+         <variablelist>
+           <varlistentry>
+             <term><option>--block-number=#[,#[...]]</option></term>
+             <listitem>
+               <para>
+                 An optional comma-separated list of block numbers to display.
+                 The first block, the STREAMINFO block, is block 0.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>--block-type=type[,type[...]]</option></term>
+             <listitem><para></para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>--except-block-type=type[,type[...]]</option></term>
+             <listitem>
+               <para>
+                 An optional comma-separated list of block types to be included
+                 or ignored with this option.  Use only one of --block-type or
+                 --except-block-type.  The valid block types are: STREAMINFO,
+                 PADDING, APPLICATION, SEEKTABLE, VORBIS_COMMENT.  You may
+                 narrow down the types of APPLICATION blocks displayed as
+                 follows:
+               </para>
+               <para>
+        APPLICATION:abcd        The APPLICATION block(s) whose textual repre-
+                                sentation of the 4-byte ID is "abcd"
+        APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-
+                                endian representation of the 4-byte ID is
+                                "0xXXXXXXXX".  For the example "abcd" above the
+                                hexadecimal equivalalent is 0x61626364
+               </para>
+               <note>
+                 <para>
+                   if both --block-number and --[except-]block-type are
+                   specified, the result is the logical AND of both
+                   arguments.</para></note>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>--application-data-format=hexdump|text</option></term>
+             <listitem>
+               <para>
+                 If the application block you are displaying contains binary
+                 data but your --data-format=text, you can display a hex dump
+                 of the application data contents instead using
+                 --application-data-format=hexdump.
+               </para>
+             </listitem>
+           </varlistentry>
+         </variablelist>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove</option></term>
+        <listitem>
+          <para>
+            Remove one or more metadata blocks from the metadata.  Unless
+            --dont-use-padding is specified, the blocks will be replaced with
+            padding.  You may not remove the STREAMINFO block.
+         </para>
+         <variablelist>
+           <varlistentry>
+             <term><option>--block-number=#[,#[...]]</option></term>
+             <listitem><para></para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>--block-type=type[,type[...]]</option></term>
+             <listitem><para></para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>--except-block-type=type[,type[...]]</option></term>
+             <listitem>
+               <para>See --list above for usage.</para>
+               <note>
+                 <para>
+                   if both --block-number and --[except-]block-type are
+                   specified, the result is the logical AND of both arguments.
+                 </para></note>
+             </listitem>
+           </varlistentry>
+         </variablelist>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--remove-all</option></term>
+        <listitem>
+          <para>
+            Remove all metadata blocks (except the STREAMINFO block) from the
+            metadata.  Unless --dont-use-padding is specified, the blocks will
+            be replaced with padding.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--merge-padding</option></term>
+        <listitem>
+          <para>
+           Merge adjacent PADDING blocks into single blocks.
+         </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>--sort-padding</option></term>
+        <listitem>
+          <para>
+           Move all PADDING blocks to the end of the metadata and merge them
+            into a single block.
+         </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>flac(1).</para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/missing b/missing
new file mode 100755 (executable)
index 0000000..fc54c64
--- /dev/null
+++ b/missing
@@ -0,0 +1,336 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# 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, 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing 0.4 - GNU automake"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  autom4te)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo "#! /bin/sh"
+       echo "# Created by GNU Automake missing as a replacement of"
+       echo "#  $ $@"
+       echo "exit 0"
+       chmod +x $file
+       exit 1
+    fi
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f y.tab.h ]; then
+       echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+        you modified a dependency of a manual page.  You may need the
+        \`Help2man' package in order for those modifications to take
+        effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+       file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+    fi
+    if [ -f "$file" ]; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo ".ab help2man is required to generate this page"
+       exit 1
+    fi
+    ;;
+
+  makeinfo)
+    if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+       # We have makeinfo, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  tar)
+    shift
+    if test -n "$run"; then
+      echo 1>&2 "ERROR: \`tar' requires --run"
+      exit 1
+    fi
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+       case "$firstarg" in
+       *o*)
+           firstarg=`echo "$firstarg" | sed s/o//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+       case "$firstarg" in
+       *h*)
+           firstarg=`echo "$firstarg" | sed s/h//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..d2d5f21
--- /dev/null
@@ -0,0 +1,111 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
+
+# process command line arguments
+while test $# -gt 0 ; do
+  case $1 in
+    -h | --help | --h*)         # -h for help
+      echo "$usage" 1>&2
+      exit 0
+      ;;
+    -m)                         # -m PERM arg
+      shift
+      test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+      dirmode=$1
+      shift
+      ;;
+    --)                         # stop option processing
+      shift
+      break
+      ;;
+    -*)                         # unknown option
+      echo "$usage" 1>&2
+      exit 1
+      ;;
+    *)                          # first non-opt arg
+      break
+      ;;
+  esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+  0) exit 0 ;;
+esac
+
+case $dirmode in
+  '')
+    if mkdir -p -- . 2>/dev/null; then
+      echo "mkdir -p -- $*"
+      exec mkdir -p -- "$@"
+    fi
+    ;;
+  *)
+    if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
+      echo "mkdir -m $dirmode -p -- $*"
+      exec mkdir -m "$dirmode" -p -- "$@"
+    fi
+    ;;
+esac
+
+for file
+do
+  set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+  shift
+
+  pathcomp=
+  for d
+  do
+    pathcomp="$pathcomp$d"
+    case $pathcomp in
+      -*) pathcomp=./$pathcomp ;;
+    esac
+
+    if test ! -d "$pathcomp"; then
+      echo "mkdir $pathcomp"
+
+      mkdir "$pathcomp" || lasterr=$?
+
+      if test ! -d "$pathcomp"; then
+       errstatus=$lasterr
+      else
+       if test ! -z "$dirmode"; then
+         echo "chmod $dirmode $pathcomp"
+         lasterr=""
+         chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+         if test ! -z "$lasterr"; then
+           errstatus=$lasterr
+         fi
+       fi
+      fi
+    fi
+
+    pathcomp="$pathcomp/"
+  done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# End:
+# mkinstalldirs ends here
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..131383e
--- /dev/null
@@ -0,0 +1,42 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__HAS_XMMS
+XMMS_DIRS = plugin_common plugin_xmms
+endif
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_DIRS = libFLAC++ test_libFLAC++
+endif
+
+SUBDIRS = \
+       libFLAC \
+       share \
+       flac \
+       metaflac \
+       monkeys_audio_utilities \
+       $(XMMS_DIRS) \
+       plugin_winamp2 \
+       test_grabbag \
+       test_libs_common \
+       test_libFLAC \
+       test_seeking \
+       test_streams \
+       $(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+       Makefile.lite
diff --git a/src/Makefile.lite b/src/Makefile.lite
new file mode 100644 (file)
index 0000000..1d496b0
--- /dev/null
@@ -0,0 +1,61 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+.PHONY: all flac libFLAC libFLAC++ metaflac plugin_common plugin_xmms share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams
+all: flac libFLAC libFLAC++ metaflac plugin_common plugin_xmms share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+flac libFLAC libFLAC++ metaflac plugin_common plugin_xmms share test_grabbag test_libs_common test_libFLAC test_libFLAC++ test_seeking test_streams:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+       -(cd flac ; $(MAKE) -f Makefile.lite clean)
+       -(cd libFLAC ; $(MAKE) -f Makefile.lite clean)
+       -(cd libFLAC++ ; $(MAKE) -f Makefile.lite clean)
+       -(cd metaflac ; $(MAKE) -f Makefile.lite clean)
+       -(cd plugin_common ; $(MAKE) -f Makefile.lite clean)
+       -(cd plugin_xmms ; $(MAKE) -f Makefile.lite clean)
+       -(cd share ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_grabbag ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_libs_common ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_libFLAC ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_libFLAC++ ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_seeking ; $(MAKE) -f Makefile.lite clean)
+       -(cd test_streams ; $(MAKE) -f Makefile.lite clean)
+
+flac: libFLAC share
+libFLAC++: libFLAC
+metaflac: libFLAC share
+plugin_common: libFLAC
+plugin_xmms: libFLAC plugin_common
+share: libFLAC
+test_grabbag: share
+test_libFLAC++: libFLAC libFLAC++ test_libs_common
+test_libFLAC: libFLAC test_libs_common
+test_seeking: libFLAC
+test_streams: libFLAC
diff --git a/src/flac/Makefile.am b/src/flac/Makefile.am
new file mode 100644 (file)
index 0000000..638cd74
--- /dev/null
@@ -0,0 +1,58 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+bin_PROGRAMS = flac
+
+AM_CFLAGS = @OGG_CFLAGS@
+
+EXTRA_DIST = \
+       Makefile.lite \
+       Makefile.lite.iffscan \
+       flac.dsp \
+       flac.vcproj \
+       iffscan.c \
+       iffscan.dsp \
+       iffscan.vcproj
+
+flac_SOURCES = \
+       analyze.c \
+       decode.c \
+       encode.c \
+       foreign_metadata.c \
+       main.c \
+       local_string_utils.c \
+       utils.c \
+       vorbiscomment.c \
+       analyze.h \
+       decode.h \
+       encode.h \
+       foreign_metadata.h \
+       local_string_utils.h \
+       utils.h \
+       vorbiscomment.h
+
+flac_LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/getopt/libgetopt.a \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+       $(top_builddir)/src/share/utf8/libutf8.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @LIBICONV@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
diff --git a/src/flac/Makefile.lite b/src/flac/Makefile.lite
new file mode 100644 (file)
index 0000000..9e8a0cc
--- /dev/null
@@ -0,0 +1,47 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = flac
+
+INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR)
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(libdir)/libreplaygain_synthesis.a $(libdir)/libgetopt.a $(libdir)/libutf8.a $(OGG_LIB_DIR)/libogg.a -liconv -lm
+else
+LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lreplaygain_synthesis -lgetopt -lutf8 -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       analyze.c \
+       decode.c \
+       encode.c \
+       foreign_metadata.c \
+       local_string_utils.c \
+       main.c \
+       utils.c \
+       vorbiscomment.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/flac/Makefile.lite.iffscan b/src/flac/Makefile.lite.iffscan
new file mode 100644 (file)
index 0000000..b12bb10
--- /dev/null
@@ -0,0 +1,41 @@
+#  flac - Command-line FLAC encoder/decoder
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = iffscan
+
+INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR)
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -liconv -lm
+else
+LIBS = -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       foreign_metadata.c \
+       iffscan.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/flac/analyze.c b/src/flac/analyze.c
new file mode 100644 (file)
index 0000000..47a5e76
--- /dev/null
@@ -0,0 +1,247 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/all.h"
+#include "analyze.h"
+
+typedef struct {
+       FLAC__int32 residual;
+       unsigned count;
+} pair_t;
+
+typedef struct {
+       pair_t buckets[FLAC__MAX_BLOCK_SIZE];
+       int peak_index;
+       unsigned nbuckets;
+       unsigned nsamples;
+       double sum, sos;
+       double variance;
+       double mean;
+       double stddev;
+} subframe_stats_t;
+
+static subframe_stats_t all_;
+
+static void init_stats(subframe_stats_t *stats);
+static void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr);
+static void compute_stats(subframe_stats_t *stats);
+static FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename);
+
+void flac__analyze_init(analysis_options aopts)
+{
+       if(aopts.do_residual_gnuplot) {
+               init_stats(&all_);
+       }
+}
+
+void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__uint64 frame_offset, unsigned frame_bytes, analysis_options aopts, FILE *fout)
+{
+       const unsigned channels = frame->header.channels;
+       char outfilename[1024];
+       subframe_stats_t stats;
+       unsigned i, channel, partitions;
+
+       /* do the human-readable part first */
+#ifdef _MSC_VER
+       fprintf(fout, "frame=%u\toffset=%I64u\tbits=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
+#else
+       fprintf(fout, "frame=%u\toffset=%llu\tbits=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, (unsigned long long)frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
+#endif
+       for(channel = 0; channel < channels; channel++) {
+               const FLAC__Subframe *subframe = frame->subframes+channel;
+               const FLAC__bool is_rice2 = subframe->data.fixed.entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2;
+               const unsigned pesc = is_rice2? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+               fprintf(fout, "\tsubframe=%u\twasted_bits=%u\ttype=%s", channel, subframe->wasted_bits, FLAC__SubframeTypeString[subframe->type]);
+               switch(subframe->type) {
+                       case FLAC__SUBFRAME_TYPE_CONSTANT:
+                               fprintf(fout, "\tvalue=%d\n", subframe->data.constant.value);
+                               break;
+                       case FLAC__SUBFRAME_TYPE_FIXED:
+                               FLAC__ASSERT(subframe->data.fixed.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2);
+                               fprintf(fout, "\torder=%u\tresidual_type=%s\tpartition_order=%u\n", subframe->data.fixed.order, is_rice2? "RICE2":"RICE", subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
+                               for(i = 0; i < subframe->data.fixed.order; i++)
+                                       fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.fixed.warmup[i]);
+                               partitions = (1u << subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
+                               for(i = 0; i < partitions; i++) {
+                                       unsigned parameter = subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
+                                       if(parameter == pesc)
+                                               fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
+                                       else
+                                               fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
+                               }
+                               if(aopts.do_residual_text) {
+                                       for(i = 0; i < frame->header.blocksize-subframe->data.fixed.order; i++)
+                                               fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.fixed.residual[i]);
+                               }
+                               break;
+                       case FLAC__SUBFRAME_TYPE_LPC:
+                               FLAC__ASSERT(subframe->data.lpc.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2);
+                               fprintf(fout, "\torder=%u\tqlp_coeff_precision=%u\tquantization_level=%d\tresidual_type=%s\tpartition_order=%u\n", subframe->data.lpc.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level, is_rice2? "RICE2":"RICE", subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order);
+                               for(i = 0; i < subframe->data.lpc.order; i++)
+                                       fprintf(fout, "\t\tqlp_coeff[%u]=%d\n", i, subframe->data.lpc.qlp_coeff[i]);
+                               for(i = 0; i < subframe->data.lpc.order; i++)
+                                       fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]);
+                               partitions = (1u << subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order);
+                               for(i = 0; i < partitions; i++) {
+                                       unsigned parameter = subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
+                                       if(parameter == pesc)
+                                               fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
+                                       else
+                                               fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
+                               }
+                               if(aopts.do_residual_text) {
+                                       for(i = 0; i < frame->header.blocksize-subframe->data.lpc.order; i++)
+                                               fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.lpc.residual[i]);
+                               }
+                               break;
+                       case FLAC__SUBFRAME_TYPE_VERBATIM:
+                               fprintf(fout, "\n");
+                               break;
+               }
+       }
+
+       /* now do the residual distributions if requested */
+       if(aopts.do_residual_gnuplot) {
+               for(channel = 0; channel < channels; channel++) {
+                       const FLAC__Subframe *subframe = frame->subframes+channel;
+                       unsigned residual_samples;
+
+                       init_stats(&stats);
+
+                       switch(subframe->type) {
+                               case FLAC__SUBFRAME_TYPE_FIXED:
+                                       residual_samples = frame->header.blocksize - subframe->data.fixed.order;
+                                       for(i = 0; i < residual_samples; i++)
+                                               update_stats(&stats, subframe->data.fixed.residual[i], 1);
+                                       break;
+                               case FLAC__SUBFRAME_TYPE_LPC:
+                                       residual_samples = frame->header.blocksize - subframe->data.lpc.order;
+                                       for(i = 0; i < residual_samples; i++)
+                                               update_stats(&stats, subframe->data.lpc.residual[i], 1);
+                                       break;
+                               default:
+                                       break;
+                       }
+
+                       /* update all_ */
+                       for(i = 0; i < stats.nbuckets; i++) {
+                               update_stats(&all_, stats.buckets[i].residual, stats.buckets[i].count);
+                       }
+
+                       /* write the subframe */
+                       sprintf(outfilename, "f%06u.s%u.gp", frame_number, channel);
+                       compute_stats(&stats);
+
+                       (void)dump_stats(&stats, outfilename);
+               }
+       }
+}
+
+void flac__analyze_finish(analysis_options aopts)
+{
+       if(aopts.do_residual_gnuplot) {
+               compute_stats(&all_);
+               (void)dump_stats(&all_, "all");
+       }
+}
+
+void init_stats(subframe_stats_t *stats)
+{
+       stats->peak_index = -1;
+       stats->nbuckets = 0;
+       stats->nsamples = 0;
+       stats->sum = 0.0;
+       stats->sos = 0.0;
+}
+
+void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr)
+{
+       unsigned i;
+       const double r = (double)residual, a = r*incr;
+
+       stats->nsamples += incr;
+       stats->sum += a;
+       stats->sos += (a*r);
+
+       for(i = 0; i < stats->nbuckets; i++) {
+               if(stats->buckets[i].residual == residual) {
+                       stats->buckets[i].count += incr;
+                       goto find_peak;
+               }
+       }
+       /* not found, make a new bucket */
+       i = stats->nbuckets;
+       stats->buckets[i].residual = residual;
+       stats->buckets[i].count = incr;
+       stats->nbuckets++;
+find_peak:
+       if(stats->peak_index < 0 || stats->buckets[i].count > stats->buckets[stats->peak_index].count)
+               stats->peak_index = i;
+}
+
+void compute_stats(subframe_stats_t *stats)
+{
+       stats->mean = stats->sum / (double)stats->nsamples;
+       stats->variance = (stats->sos - (stats->sum * stats->sum / stats->nsamples)) / stats->nsamples;
+       stats->stddev = sqrt(stats->variance);
+}
+
+FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename)
+{
+       FILE *outfile;
+       unsigned i;
+       const double m = stats->mean;
+       const double s1 = stats->stddev, s2 = s1*2, s3 = s1*3, s4 = s1*4, s5 = s1*5, s6 = s1*6;
+       const double p = stats->buckets[stats->peak_index].count;
+
+       outfile = fopen(filename, "w");
+
+       if(0 == outfile) {
+               fprintf(stderr, "ERROR opening %s: %s\n", filename, strerror(errno));
+               return false;
+       }
+
+       fprintf(outfile, "plot '-' title 'PDF', '-' title 'mean' with impulses, '-' title '1-stddev' with histeps, '-' title '2-stddev' with histeps, '-' title '3-stddev' with histeps, '-' title '4-stddev' with histeps, '-' title '5-stddev' with histeps, '-' title '6-stddev' with histeps\n");
+
+       for(i = 0; i < stats->nbuckets; i++) {
+               fprintf(outfile, "%d %u\n", stats->buckets[i].residual, stats->buckets[i].count);
+       }
+       fprintf(outfile, "e\n");
+
+       fprintf(outfile, "%f %f\ne\n", stats->mean, p);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s1, p*0.8, m+s1, p*0.8);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s2, p*0.7, m+s2, p*0.7);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s3, p*0.6, m+s3, p*0.6);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s4, p*0.5, m+s4, p*0.5);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s5, p*0.4, m+s5, p*0.4);
+       fprintf(outfile, "%f %f\n%f %f\ne\n", m-s6, p*0.3, m+s6, p*0.3);
+
+       fprintf(outfile, "pause -1 'waiting...'\n");
+
+       fclose(outfile);
+       return true;
+}
diff --git a/src/flac/analyze.h b/src/flac/analyze.h
new file mode 100644 (file)
index 0000000..b58b6b8
--- /dev/null
@@ -0,0 +1,31 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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__analyze_h
+#define flac__analyze_h
+
+typedef struct {
+       FLAC__bool do_residual_text;
+       FLAC__bool do_residual_gnuplot;
+} analysis_options;
+
+void flac__analyze_init(analysis_options aopts);
+void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__uint64 frame_offset, unsigned frame_bytes, analysis_options aopts, FILE *fout);
+void flac__analyze_finish(analysis_options aopts);
+
+#endif
diff --git a/src/flac/decode.c b/src/flac/decode.c
new file mode 100644 (file)
index 0000000..1e537c0
--- /dev/null
@@ -0,0 +1,1380 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include <errno.h>
+#include <math.h> /* for floor() */
+#include <stdio.h> /* for FILE etc. */
+#include <string.h> /* for strcmp(), strerror() */
+#include "FLAC/all.h"
+#include "share/grabbag.h"
+#include "share/replaygain_synthesis.h"
+#include "decode.h"
+
+typedef struct {
+#if FLAC__HAS_OGG
+       FLAC__bool is_ogg;
+       FLAC__bool use_first_serial_number;
+       long serial_number;
+#endif
+
+       FLAC__bool is_aiff_out;
+       FLAC__bool is_wave_out;
+       FLAC__bool treat_warnings_as_errors;
+       FLAC__bool continue_through_decode_errors;
+       FLAC__bool channel_map_none;
+
+       struct {
+               replaygain_synthesis_spec_t spec;
+               FLAC__bool apply; /* 'spec.apply' is just a request; this 'apply' means we actually parsed the RG tags and are ready to go */
+               double scale;
+               DitherContext dither_context;
+       } replaygain;
+
+       FLAC__bool test_only;
+       FLAC__bool analysis_mode;
+       analysis_options aopts;
+       utils__SkipUntilSpecification *skip_specification;
+       utils__SkipUntilSpecification *until_specification; /* a canonicalized value of 0 mean end-of-stream (i.e. --until=-0) */
+       utils__CueSpecification *cue_specification;
+
+       const char *inbasefilename;
+       const char *infilename;
+       const char *outfilename;
+
+       FLAC__uint64 samples_processed;
+       unsigned frame_counter;
+       FLAC__bool abort_flag;
+       FLAC__bool aborting_due_to_until; /* true if we intentionally abort decoding prematurely because we hit the --until point */
+       FLAC__bool aborting_due_to_unparseable; /* true if we abort decoding because we hit an unparseable frame */
+
+       FLAC__bool iff_headers_need_fixup;
+
+       FLAC__bool is_big_endian;
+       FLAC__bool is_unsigned_samples;
+       FLAC__bool got_stream_info;
+       FLAC__bool has_md5sum;
+       FLAC__uint64 total_samples;
+       unsigned bps;
+       unsigned channels;
+       unsigned sample_rate;
+       FLAC__uint32 channel_mask;
+
+       /* these are used only in analyze mode */
+       FLAC__uint64 decode_position;
+
+       FLAC__StreamDecoder *decoder;
+
+       FILE *fout;
+
+       foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+       off_t fm_offset1, fm_offset2, fm_offset3;
+} DecoderSession;
+
+
+static FLAC__bool is_big_endian_host_;
+
+
+/*
+ * local routines
+ */
+static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename);
+static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
+static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, const char *infilename);
+static FLAC__bool DecoderSession_process(DecoderSession *d);
+static int DecoderSession_finish_ok(DecoderSession *d);
+static int DecoderSession_finish_error(DecoderSession *d);
+static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
+static FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples);
+static FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask);
+static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bps, unsigned channels, unsigned sample_rate);
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
+static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val);
+static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val);
+static FLAC__bool write_sane_extended(FILE *f, unsigned val);
+static FLAC__bool fixup_iff_headers(DecoderSession *d);
+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 void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status);
+static void print_error_with_state(const DecoderSession *d, const char *message);
+static void print_stats(const DecoderSession *decoder_session);
+
+
+/*
+ * public routines
+ */
+int flac__decode_aiff(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
+{
+       DecoderSession decoder_session;
+
+       if(!
+               DecoderSession_construct(
+                       &decoder_session,
+#if FLAC__HAS_OGG
+                       options.common.is_ogg,
+                       options.common.use_first_serial_number,
+                       options.common.serial_number,
+#else
+                       /*is_ogg=*/false,
+                       /*use_first_serial_number=*/false,
+                       /*serial_number=*/0,
+#endif
+                       /*is_aiff_out=*/true,
+                       /*is_wave_out=*/false,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       options.common.channel_map_none,
+                       options.common.replaygain_synthesis_spec,
+                       analysis_mode,
+                       aopts,
+                       &options.common.skip_specification,
+                       &options.common.until_specification,
+                       options.common.has_cue_specification? &options.common.cue_specification : 0,
+                       options.foreign_metadata,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       if(!DecoderSession_init_decoder(&decoder_session, infilename))
+               return DecoderSession_finish_error(&decoder_session);
+
+       if(!DecoderSession_process(&decoder_session))
+               return DecoderSession_finish_error(&decoder_session);
+
+       return DecoderSession_finish_ok(&decoder_session);
+}
+
+int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
+{
+       DecoderSession decoder_session;
+
+       if(!
+               DecoderSession_construct(
+                       &decoder_session,
+#if FLAC__HAS_OGG
+                       options.common.is_ogg,
+                       options.common.use_first_serial_number,
+                       options.common.serial_number,
+#else
+                       /*is_ogg=*/false,
+                       /*use_first_serial_number=*/false,
+                       /*serial_number=*/0,
+#endif
+                       /*is_aiff_out=*/false,
+                       /*is_wave_out=*/true,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       options.common.channel_map_none,
+                       options.common.replaygain_synthesis_spec,
+                       analysis_mode,
+                       aopts,
+                       &options.common.skip_specification,
+                       &options.common.until_specification,
+                       options.common.has_cue_specification? &options.common.cue_specification : 0,
+                       options.foreign_metadata,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       if(!DecoderSession_init_decoder(&decoder_session, infilename))
+               return DecoderSession_finish_error(&decoder_session);
+
+       if(!DecoderSession_process(&decoder_session))
+               return DecoderSession_finish_error(&decoder_session);
+
+       return DecoderSession_finish_ok(&decoder_session);
+}
+
+int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options)
+{
+       DecoderSession decoder_session;
+
+       decoder_session.is_big_endian = options.is_big_endian;
+       decoder_session.is_unsigned_samples = options.is_unsigned_samples;
+
+       if(!
+               DecoderSession_construct(
+                       &decoder_session,
+#if FLAC__HAS_OGG
+                       options.common.is_ogg,
+                       options.common.use_first_serial_number,
+                       options.common.serial_number,
+#else
+                       /*is_ogg=*/false,
+                       /*use_first_serial_number=*/false,
+                       /*serial_number=*/0,
+#endif
+                       /*is_aiff_out=*/false,
+                       /*is_wave_out=*/false,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       options.common.channel_map_none,
+                       options.common.replaygain_synthesis_spec,
+                       analysis_mode,
+                       aopts,
+                       &options.common.skip_specification,
+                       &options.common.until_specification,
+                       options.common.has_cue_specification? &options.common.cue_specification : 0,
+                       /*foreign_metadata=*/NULL,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       if(!DecoderSession_init_decoder(&decoder_session, infilename))
+               return DecoderSession_finish_error(&decoder_session);
+
+       if(!DecoderSession_process(&decoder_session))
+               return DecoderSession_finish_error(&decoder_session);
+
+       return DecoderSession_finish_ok(&decoder_session);
+}
+
+FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename)
+{
+#if FLAC__HAS_OGG
+       d->is_ogg = is_ogg;
+       d->use_first_serial_number = use_first_serial_number;
+       d->serial_number = serial_number;
+#else
+       (void)is_ogg;
+       (void)use_first_serial_number;
+       (void)serial_number;
+#endif
+
+       d->is_aiff_out = is_aiff_out;
+       d->is_wave_out = is_wave_out;
+       d->treat_warnings_as_errors = treat_warnings_as_errors;
+       d->continue_through_decode_errors = continue_through_decode_errors;
+       d->channel_map_none = channel_map_none;
+       d->replaygain.spec = replaygain_synthesis_spec;
+       d->replaygain.apply = false;
+       d->replaygain.scale = 0.0;
+       /* d->replaygain.dither_context gets initialized later once we know the sample resolution */
+       d->test_only = (0 == outfilename);
+       d->analysis_mode = analysis_mode;
+       d->aopts = aopts;
+       d->skip_specification = skip_specification;
+       d->until_specification = until_specification;
+       d->cue_specification = cue_specification;
+
+       d->inbasefilename = grabbag__file_get_basename(infilename);
+       d->infilename = infilename;
+       d->outfilename = outfilename;
+
+       d->samples_processed = 0;
+       d->frame_counter = 0;
+       d->abort_flag = false;
+       d->aborting_due_to_until = false;
+       d->aborting_due_to_unparseable = false;
+
+       d->iff_headers_need_fixup = false;
+
+       d->total_samples = 0;
+       d->got_stream_info = false;
+       d->has_md5sum = false;
+       d->bps = 0;
+       d->channels = 0;
+       d->sample_rate = 0;
+       d->channel_mask = 0;
+
+       d->decode_position = 0;
+
+       d->decoder = 0;
+
+       d->fout = 0; /* initialized with an open file later if necessary */
+
+       d->foreign_metadata = foreign_metadata;
+
+       FLAC__ASSERT(!(d->test_only && d->analysis_mode));
+
+       if(!d->test_only) {
+               if(0 == strcmp(outfilename, "-")) {
+                       d->fout = grabbag__file_get_binary_stdout();
+               }
+               else {
+                       if(0 == (d->fout = fopen(outfilename, "wb"))) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: can't open output file %s: %s\n", d->inbasefilename, outfilename, strerror(errno));
+                               DecoderSession_destroy(d, /*error_occurred=*/true);
+                               return false;
+                       }
+               }
+       }
+
+       if(analysis_mode)
+               flac__analyze_init(aopts);
+
+       return true;
+}
+
+void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred)
+{
+       if(0 != d->fout && d->fout != stdout) {
+               fclose(d->fout);
+               if(error_occurred)
+                       unlink(d->outfilename);
+       }
+}
+
+FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const char *infilename)
+{
+       FLAC__StreamDecoderInitStatus init_status;
+       FLAC__uint32 test = 1;
+
+       is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+       if(!decoder_session->analysis_mode && !decoder_session->test_only && (decoder_session->is_wave_out || decoder_session->is_aiff_out)) {
+               if(decoder_session->foreign_metadata) {
+                       const char *error;
+                       if(!flac__foreign_metadata_read_from_flac(decoder_session->foreign_metadata, infilename, &error)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", decoder_session->inbasefilename, error);
+                               return false;
+                       }
+               }
+       }
+
+       decoder_session->decoder = FLAC__stream_decoder_new();
+
+       if(0 == decoder_session->decoder) {
+               flac__utils_printf(stderr, 1, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename);
+               return false;
+       }
+
+       FLAC__stream_decoder_set_md5_checking(decoder_session->decoder, true);
+       if (0 != decoder_session->cue_specification)
+               FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_CUESHEET);
+       if (decoder_session->replaygain.spec.apply)
+               FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+#if FLAC__HAS_OGG
+       if(decoder_session->is_ogg) {
+               if(!decoder_session->use_first_serial_number)
+                       FLAC__stream_decoder_set_ogg_serial_number(decoder_session->decoder, decoder_session->serial_number);
+               init_status = FLAC__stream_decoder_init_ogg_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session);
+       }
+       else
+#endif
+       {
+               init_status = FLAC__stream_decoder_init_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session);
+       }
+
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               print_error_with_init_status(decoder_session, "ERROR initializing decoder", init_status);
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool DecoderSession_process(DecoderSession *d)
+{
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(d->decoder)) {
+               flac__utils_printf(stderr, 2, "\n");
+               print_error_with_state(d, "ERROR while decoding metadata");
+               return false;
+       }
+       if(FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) {
+               flac__utils_printf(stderr, 2, "\n");
+               print_error_with_state(d, "ERROR during metadata decoding");
+               if(!d->continue_through_decode_errors)
+                       return false;
+       }
+
+       if(d->abort_flag)
+               return false;
+
+       /* set channel mapping */
+       if(!d->channel_map_none) {
+               /* currently FLAC order matches SMPTE/WAVEFORMATEXTENSIBLE order, so no reordering is necessary; see encode.c */
+               /* only the channel mask must be set if it was not already picked up from the WAVEFORMATEXTENSIBLE_CHANNEL_MASK tag */
+               if(d->channels == 1) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x0001;
+               }
+               else if(d->channels == 2) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x0003;
+               }
+               else if(d->channels == 3) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x0007;
+               }
+               else if(d->channels == 4) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x0033;
+               }
+               else if(d->channels == 5) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x0607;
+               }
+               else if(d->channels == 6) {
+                       if(d->channel_mask == 0)
+                               d->channel_mask = 0x060f;
+               }
+       }
+
+       /* write the WAVE/AIFF headers if necessary */
+       if(!d->analysis_mode && !d->test_only && (d->is_wave_out || d->is_aiff_out)) {
+               if(!write_iff_headers(d->fout, d, d->total_samples)) {
+                       d->abort_flag = true;
+                       return false;
+               }
+       }
+
+       if(d->skip_specification->value.samples > 0) {
+               const FLAC__uint64 skip = (FLAC__uint64)d->skip_specification->value.samples;
+
+               if(!FLAC__stream_decoder_seek_absolute(d->decoder, skip)) {
+                       print_error_with_state(d, "ERROR seeking while skipping bytes");
+                       return false;
+               }
+       }
+       if(!FLAC__stream_decoder_process_until_end_of_stream(d->decoder) && !d->aborting_due_to_until) {
+               flac__utils_printf(stderr, 2, "\n");
+               print_error_with_state(d, "ERROR while decoding data");
+               if(!d->continue_through_decode_errors)
+                       return false;
+       }
+       if(
+               (d->abort_flag && !(d->aborting_due_to_until || d->continue_through_decode_errors)) ||
+               (FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM && !d->aborting_due_to_until)
+       ) {
+               flac__utils_printf(stderr, 2, "\n");
+               print_error_with_state(d, "ERROR during decoding");
+               return false;
+       }
+
+       if(!d->analysis_mode && !d->test_only && (d->is_wave_out || d->is_aiff_out) && ((d->total_samples * d->channels * ((d->bps+7)/8)) & 1)) {
+               if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) {
+                       print_error_with_state(d, d->is_wave_out?
+                               "ERROR writing pad byte to WAVE data chunk" :
+                               "ERROR writing pad byte to AIFF SSND chunk"
+                       );
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+int DecoderSession_finish_ok(DecoderSession *d)
+{
+       FLAC__bool ok = true, md5_failure = false;
+
+       if(d->decoder) {
+               md5_failure = !FLAC__stream_decoder_finish(d->decoder) && !d->aborting_due_to_until;
+               print_stats(d);
+               FLAC__stream_decoder_delete(d->decoder);
+       }
+       if(d->analysis_mode)
+               flac__analyze_finish(d->aopts);
+       if(md5_failure) {
+               flac__utils_printf(stderr, 1, "\r%s: ERROR, MD5 signature mismatch\n", d->inbasefilename);
+               ok = d->continue_through_decode_errors;
+       }
+       else {
+               if(!d->got_stream_info) {
+                       flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since there was no STREAMINFO\n", d->inbasefilename);
+                       ok = !d->treat_warnings_as_errors;
+               }
+               else if(!d->has_md5sum) {
+                       flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n", d->inbasefilename);
+                       ok = !d->treat_warnings_as_errors;
+               }
+               flac__utils_printf(stderr, 2, "\r%s: %s         \n", d->inbasefilename, d->test_only? "ok           ":d->analysis_mode?"done           ":"done");
+       }
+       DecoderSession_destroy(d, /*error_occurred=*/!ok);
+       if(!d->analysis_mode && !d->test_only && (d->is_wave_out || d->is_aiff_out)) {
+               if(d->iff_headers_need_fixup || (!d->got_stream_info && strcmp(d->outfilename, "-"))) {
+                       if(!fixup_iff_headers(d))
+                               return 1;
+               }
+               if(d->foreign_metadata) {
+                       const char *error;
+                       if(!flac__foreign_metadata_write_to_iff(d->foreign_metadata, d->infilename, d->outfilename, d->fm_offset1, d->fm_offset2, d->fm_offset3, &error)) {
+                               flac__utils_printf(stderr, 1, "ERROR updating foreign metadata from %s to %s: %s\n", d->infilename, d->outfilename, error);
+                               return 1;
+                       }
+               }
+       }
+       return ok? 0 : 1;
+}
+
+int DecoderSession_finish_error(DecoderSession *d)
+{
+       if(d->decoder) {
+               (void)FLAC__stream_decoder_finish(d->decoder);
+               FLAC__stream_decoder_delete(d->decoder);
+       }
+       if(d->analysis_mode)
+               flac__analyze_finish(d->aopts);
+       DecoderSession_destroy(d, /*error_occurred=*/true);
+       return 1;
+}
+
+FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+       /* convert from mm:ss.sss to sample number if necessary */
+       flac__utils_canonicalize_skip_until_specification(spec, sample_rate);
+
+       /* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */
+       if(spec->is_relative && spec->value.samples == 0) {
+               spec->is_relative = false;
+               return true;
+       }
+
+       /* in any other case the total samples in the input must be known */
+       if(total_samples_in_input == 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when FLAC metadata has total sample count of 0\n", inbasefilename);
+               return false;
+       }
+
+       FLAC__ASSERT(spec->value_is_samples);
+
+       /* convert relative specifications to absolute */
+       if(spec->is_relative) {
+               if(spec->value.samples <= 0)
+                       spec->value.samples += (FLAC__int64)total_samples_in_input;
+               else
+                       spec->value.samples += skip;
+               spec->is_relative = false;
+       }
+
+       /* error check */
+       if(spec->value.samples < 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename);
+               return false;
+       }
+       if((FLAC__uint64)spec->value.samples <= skip) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename);
+               return false;
+       }
+       if((FLAC__uint64)spec->value.samples > total_samples_in_input) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename);
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples)
+{
+       const char *fmt_desc = decoder_session->is_wave_out? "WAVE" : "AIFF";
+       const FLAC__bool is_waveformatextensible = decoder_session->is_wave_out && (decoder_session->channel_mask == 2 || decoder_session->channel_mask > 3 || decoder_session->bps%8 || decoder_session->channels > 2);
+       FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8);
+       const FLAC__uint32 aligned_data_size = (FLAC__uint32)((data_size+1) & (~1U)); /* we'll check for overflow later */
+
+       unsigned foreign_metadata_size = 0; /* size of all non-audio non-fmt/COMM foreign metadata chunks */
+       foreign_metadata_t *fm = decoder_session->foreign_metadata;
+       size_t i;
+
+       if(samples == 0) {
+               if(f == stdout) {
+                       flac__utils_printf(stderr, 1, "%s: WARNING, don't have accurate sample count available for %s header.\n", decoder_session->inbasefilename, fmt_desc);
+                       flac__utils_printf(stderr, 1, "             Generated %s file will have a data chunk size of 0.  Try\n", fmt_desc);
+                       flac__utils_printf(stderr, 1, "             decoding directly to a file instead.\n");
+                       if(decoder_session->treat_warnings_as_errors)
+                               return false;
+               }
+               else {
+                       decoder_session->iff_headers_need_fixup = true;
+               }
+       }
+
+       if(fm) {
+               FLAC__ASSERT(fm->format_block);
+               FLAC__ASSERT(fm->audio_block);
+               FLAC__ASSERT(fm->format_block < fm->audio_block);
+               /* calc foreign metadata size; for RIFF/AIFF we always skip the first chunk, format chunk, and sound chunk since we write our own */
+               for(i = 1; i < fm->num_blocks; i++) {
+                       if(i != fm->format_block && i != fm->audio_block)
+                               foreign_metadata_size += fm->blocks[i].size;
+               }
+       }
+
+       if(data_size + foreign_metadata_size + 60/*worst-case*/ >= 0xFFFFFFF4) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: stream is too big to fit in a single %s file\n", decoder_session->inbasefilename, fmt_desc);
+               return false;
+       }
+
+       if(decoder_session->is_wave_out) {
+               if(flac__utils_fwrite("RIFF", 1, 4, f) != 4)
+                       return false;
+
+               if(!write_little_endian_uint32(f, foreign_metadata_size + aligned_data_size + (is_waveformatextensible?60:36))) /* filesize-8 */
+                       return false;
+
+               if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+                       return false;
+
+               decoder_session->fm_offset1 = ftello(f);
+
+               if(fm) {
+                       /* seek forward to {allocate} or {skip over already-written chunks} before "fmt " */
+                       for(i = 1; i < fm->format_block; i++) {
+                               if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"fmt \"\n", decoder_session->inbasefilename);
+                                       return false;
+                               }
+                       }
+               }
+
+               if(!write_riff_wave_fmt_chunk(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask))
+                       return false;
+
+               decoder_session->fm_offset2 = ftello(f);
+
+               if(fm) {
+                       /* seek forward to {allocate} or {skip over already-written chunks} after "fmt " but before "data" */
+                       for(i = fm->format_block+1; i < fm->audio_block; i++) {
+                               if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"fmt \"\n", decoder_session->inbasefilename);
+                                       return false;
+                               }
+                       }
+               }
+
+               if(flac__utils_fwrite("data", 1, 4, f) != 4)
+                       return false;
+
+               if(!write_little_endian_uint32(f, (FLAC__uint32)data_size)) /* data size */
+                       return false;
+
+               decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+       }
+       else {
+               FLAC__uint32 ssnd_offset_size = (fm? fm->ssnd_offset_size : 0);
+
+               if(flac__utils_fwrite("FORM", 1, 4, f) != 4)
+                       return false;
+
+               if(!write_big_endian_uint32(f, foreign_metadata_size + aligned_data_size + 46 + ssnd_offset_size)) /* filesize-8 */
+                       return false;
+
+               if(flac__utils_fwrite("AIFF", 1, 4, f) != 4)
+                       return false;
+
+               decoder_session->fm_offset1 = ftello(f);
+
+               if(fm) {
+                       /* seek forward to {allocate} or {skip over already-written chunks} before "COMM" */
+                       for(i = 1; i < fm->format_block; i++) {
+                               if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"COMM\"\n", decoder_session->inbasefilename);
+                                       return false;
+                               }
+                       }
+               }
+
+               if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate))
+                       return false;
+
+               decoder_session->fm_offset2 = ftello(f);
+
+               if(fm) {
+                       /* seek forward to {allocate} or {skip over already-written chunks} after "COMM" but before "SSND" */
+                       for(i = fm->format_block+1; i < fm->audio_block; i++) {
+                               if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"COMM\"\n", decoder_session->inbasefilename);
+                                       return false;
+                               }
+                       }
+               }
+
+               if(flac__utils_fwrite("SSND", 1, 4, f) != 4)
+                       return false;
+
+               if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8 + ssnd_offset_size)) /* data size */
+                       return false;
+
+               if(!write_big_endian_uint32(f, ssnd_offset_size))
+                       return false;
+
+               if(!write_big_endian_uint32(f, 0/*block_size*/))
+                       return false;
+
+               if(ssnd_offset_size) {
+                       /* seek forward to {allocate} or {skip over already-written} SSND offset */
+                       if(fseeko(f, ssnd_offset_size, SEEK_CUR) < 0) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping \"SSND\" offset\n", decoder_session->inbasefilename);
+                               return false;
+                       }
+               }
+
+               decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+       }
+
+       return true;
+}
+
+FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask)
+{
+       if(flac__utils_fwrite("fmt ", 1, 4, f) != 4)
+               return false;
+
+       if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */
+               return false;
+
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(is_waveformatextensible? 65534 : 1))) /* compression code */
+               return false;
+
+       if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
+               return false;
+
+       if(!write_little_endian_uint32(f, sample_rate))
+               return false;
+
+       if(!write_little_endian_uint32(f, sample_rate * channels * ((bps+7) / 8)))
+               return false;
+
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * ((bps+7) / 8)))) /* block align */
+               return false;
+
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(((bps+7)/8)*8))) /* bits per sample */
+               return false;
+
+       if(is_waveformatextensible) {
+               if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */
+                       return false;
+
+               if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */
+                       return false;
+
+               if(!write_little_endian_uint32(f, channel_mask))
+                       return false;
+
+               /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+               if(flac__utils_fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+                       return false;
+       }
+
+       return true;
+}
+
+FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bps, unsigned channels, unsigned sample_rate)
+{
+       FLAC__ASSERT(samples <= 0xffffffff);
+
+       if(flac__utils_fwrite("COMM", 1, 4, f) != 4)
+               return false;
+
+       if(!write_big_endian_uint32(f, 18)) /* chunk size = 18 */
+               return false;
+
+       if(!write_big_endian_uint16(f, (FLAC__uint16)channels))
+               return false;
+
+       if(!write_big_endian_uint32(f, (FLAC__uint32)samples))
+               return false;
+
+       if(!write_big_endian_uint16(f, (FLAC__uint16)bps))
+               return false;
+
+       if(!write_sane_extended(f, sample_rate))
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val)
+{
+       FLAC__byte *b = (FLAC__byte*)(&val);
+       if(is_big_endian_host_) {
+               FLAC__byte tmp;
+               tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+       }
+       return flac__utils_fwrite(b, 1, 2, f) == 2;
+}
+
+FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val)
+{
+       FLAC__byte *b = (FLAC__byte*)(&val);
+       if(is_big_endian_host_) {
+               FLAC__byte tmp;
+               tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+               tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+       }
+       return flac__utils_fwrite(b, 1, 4, f) == 4;
+}
+
+FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val)
+{
+       FLAC__byte *b = (FLAC__byte*)(&val);
+       if(!is_big_endian_host_) {
+               FLAC__byte tmp;
+               tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+       }
+       return flac__utils_fwrite(b, 1, 2, f) == 2;
+}
+
+FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val)
+{
+       FLAC__byte *b = (FLAC__byte*)(&val);
+       if(!is_big_endian_host_) {
+               FLAC__byte tmp;
+               tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+               tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+       }
+       return flac__utils_fwrite(b, 1, 4, f) == 4;
+}
+
+FLAC__bool write_sane_extended(FILE *f, unsigned val)
+       /* Write to 'f' a SANE extended representation of 'val'.  Return false if
+       * the write succeeds; return true otherwise.
+       *
+       * SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits
+       * of exponent, and 64 bits of significand (mantissa).  Unlike most IEEE-754
+       * representations, it does not imply a 1 above the MSB of the significand.
+       *
+       * Preconditions:
+       *  val!=0U
+       */
+{
+       unsigned int shift, exponent;
+
+       FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */
+
+       for(shift= 0U; (val>>(31-shift))==0U; ++shift)
+               ;
+       val<<= shift;
+       exponent= 63U-(shift+32U); /* add 32 for unused second word */
+
+       if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF)))
+               return false;
+       if(!write_big_endian_uint32(f, val))
+               return false;
+       if(!write_big_endian_uint32(f, 0)) /* unused second word */
+               return false;
+
+       return true;
+}
+
+FLAC__bool fixup_iff_headers(DecoderSession *d)
+{
+       const char *fmt_desc = (d->is_wave_out? "WAVE" : "AIFF");
+       FILE *f = fopen(d->outfilename, "r+b"); /* stream is positioned at beginning of file */
+
+       if(0 == f) {
+               flac__utils_printf(stderr, 1, "ERROR, couldn't open file %s while fixing up %s chunk size: %s\n", d->outfilename, fmt_desc, strerror(errno));
+               return false;
+       }
+
+       if(!write_iff_headers(f, d, d->samples_processed)) {
+               fclose(f);
+               return false;
+       }
+
+       fclose(f);
+       return true;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       DecoderSession *decoder_session = (DecoderSession*)client_data;
+       FILE *fout = decoder_session->fout;
+       const unsigned bps = frame->header.bits_per_sample, channels = frame->header.channels;
+       const unsigned shift = ((decoder_session->is_wave_out || decoder_session->is_aiff_out) && (bps%8)? 8-(bps%8): 0);
+       FLAC__bool is_big_endian = (decoder_session->is_aiff_out? true : (decoder_session->is_wave_out? false : decoder_session->is_big_endian));
+       FLAC__bool is_unsigned_samples = (decoder_session->is_aiff_out? false : (decoder_session->is_wave_out? bps<=8 : decoder_session->is_unsigned_samples));
+       unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
+       unsigned frame_bytes = 0;
+       static FLAC__int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */
+       FLAC__uint8  *u8buffer  = (FLAC__uint8  *)s8buffer;
+       FLAC__int16  *s16buffer = (FLAC__int16  *)s8buffer;
+       FLAC__uint16 *u16buffer = (FLAC__uint16 *)s8buffer;
+       FLAC__int32  *s32buffer = (FLAC__int32  *)s8buffer;
+       FLAC__uint32 *u32buffer = (FLAC__uint32 *)s8buffer;
+       size_t bytes_to_write = 0;
+
+       (void)decoder;
+
+       if(decoder_session->abort_flag)
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+       /* sanity-check the bits-per-sample */
+       if(decoder_session->bps) {
+               if(bps != decoder_session->bps) {
+                       if(decoder_session->got_stream_info)
+                               flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, bps, decoder_session->bps);
+                       else
+                               flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, bps, decoder_session->bps);
+                       if(!decoder_session->continue_through_decode_errors)
+                               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       else {
+               /* must not have gotten STREAMINFO, save the bps from the frame header */
+               FLAC__ASSERT(!decoder_session->got_stream_info);
+               decoder_session->bps = bps;
+       }
+
+       /* sanity-check the #channels */
+       if(decoder_session->channels) {
+               if(channels != decoder_session->channels) {
+                       if(decoder_session->got_stream_info)
+                               flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, channels, decoder_session->channels);
+                       else
+                               flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, channels, decoder_session->channels);
+                       if(!decoder_session->continue_through_decode_errors)
+                               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       else {
+               /* must not have gotten STREAMINFO, save the #channels from the frame header */
+               FLAC__ASSERT(!decoder_session->got_stream_info);
+               decoder_session->channels = channels;
+       }
+
+       /* sanity-check the sample rate */
+       if(decoder_session->sample_rate) {
+               if(frame->header.sample_rate != decoder_session->sample_rate) {
+                       if(decoder_session->got_stream_info)
+                               flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate);
+                       else
+                               flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate);
+                       if(!decoder_session->continue_through_decode_errors)
+                               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       else {
+               /* must not have gotten STREAMINFO, save the sample rate from the frame header */
+               FLAC__ASSERT(!decoder_session->got_stream_info);
+               decoder_session->sample_rate = frame->header.sample_rate;
+       }
+
+       /*
+        * limit the number of samples to accept based on --until
+        */
+       FLAC__ASSERT(!decoder_session->skip_specification->is_relative);
+       /* if we never got the total_samples from the metadata, the skip and until specs would never have been canonicalized, so protect against that: */
+       if(decoder_session->skip_specification->is_relative) {
+               if(decoder_session->skip_specification->value.samples == 0) /* special case for when no --skip was given */
+                       decoder_session->skip_specification->is_relative = false; /* convert to our meaning of beginning-of-stream */
+               else {
+                       flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --skip because the total sample count was not found in the metadata\n", decoder_session->inbasefilename);
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       if(decoder_session->until_specification->is_relative) {
+               if(decoder_session->until_specification->value.samples == 0) /* special case for when no --until was given */
+                       decoder_session->until_specification->is_relative = false; /* convert to our meaning of end-of-stream */
+               else {
+                       flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until because the total sample count was not found in the metadata\n", decoder_session->inbasefilename);
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+       FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+       if(decoder_session->until_specification->value.samples > 0) {
+               const FLAC__uint64 skip = (FLAC__uint64)decoder_session->skip_specification->value.samples;
+               const FLAC__uint64 until = (FLAC__uint64)decoder_session->until_specification->value.samples;
+               const FLAC__uint64 input_samples_passed = skip + decoder_session->samples_processed;
+               FLAC__ASSERT(until >= input_samples_passed);
+               if(input_samples_passed + wide_samples > until)
+                       wide_samples = (unsigned)(until - input_samples_passed);
+               if (wide_samples == 0) {
+                       decoder_session->abort_flag = true;
+                       decoder_session->aborting_due_to_until = true;
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+
+       if(decoder_session->analysis_mode) {
+               FLAC__uint64 dpos;
+               FLAC__stream_decoder_get_decode_position(decoder_session->decoder, &dpos);
+               frame_bytes = (unsigned)(dpos-decoder_session->decode_position);
+               decoder_session->decode_position = dpos;
+       }
+
+       if(wide_samples > 0) {
+               decoder_session->samples_processed += wide_samples;
+               decoder_session->frame_counter++;
+
+               if(!(decoder_session->frame_counter & 0x3f))
+                       print_stats(decoder_session);
+
+               if(decoder_session->analysis_mode) {
+                       flac__analyze_frame(frame, decoder_session->frame_counter-1, decoder_session->decode_position-frame_bytes, frame_bytes, decoder_session->aopts, fout);
+               }
+               else if(!decoder_session->test_only) {
+                       if(shift && !decoder_session->replaygain.apply) {
+                               for(wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                       for(channel = 0; channel < channels; channel++)
+                                               ((FLAC__int32**)buffer)[channel][wide_sample] <<= shift;/*@@@@@@un-const'ing the buffer is hacky but safe*/
+                       }
+                       if(decoder_session->replaygain.apply) {
+                               bytes_to_write = FLAC__replaygain_synthesis__apply_gain(
+                                       u8buffer,
+                                       !is_big_endian,
+                                       is_unsigned_samples,
+                                       buffer,
+                                       wide_samples,
+                                       channels,
+                                       bps, /* source_bps */
+                                       bps+shift, /* target_bps */
+                                       decoder_session->replaygain.scale,
+                                       decoder_session->replaygain.spec.limiter == RGSS_LIMIT__HARD, /* hard_limit */
+                                       decoder_session->replaygain.spec.noise_shaping != NOISE_SHAPING_NONE, /* do_dithering */
+                                       &decoder_session->replaygain.dither_context
+                               );
+                       }
+                       /* first some special code for common cases */
+                       else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 2 && bps+shift == 16) {
+                               FLAC__int16 *buf1_ = s16buffer + 1;
+                               if(is_big_endian)
+                                       memcpy(s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2);
+                               else
+                                       memcpy(s16buffer, buffer[0], sizeof(FLAC__int32) * wide_samples);
+                               for(sample = 0; sample < wide_samples; sample++, buf1_+=2)
+                                       *buf1_ = (FLAC__int16)buffer[1][sample];
+                               bytes_to_write = 4 * sample;
+                       }
+                       else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 1 && bps+shift == 16) {
+                               FLAC__int16 *buf1_ = s16buffer;
+                               for(sample = 0; sample < wide_samples; sample++)
+                                       *buf1_++ = (FLAC__int16)buffer[0][sample];
+                               bytes_to_write = 2 * sample;
+                       }
+                       /* generic code for the rest */
+                       else if(bps+shift == 16) {
+                               if(is_unsigned_samples) {
+                                       if(channels == 2) {
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+                                                       u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
+                                                       u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000);
+                                               }
+                                       }
+                                       else if(channels == 1) {
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                                       u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
+                                       }
+                                       else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                                       for(channel = 0; channel < channels; channel++, sample++)
+                                                               u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000);
+                                       }
+                               }
+                               else {
+                                       if(channels == 2) {
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+                                                       s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+                                                       s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]);
+                                               }
+                                       }
+                                       else if(channels == 1) {
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                                       s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+                                       }
+                                       else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
+                                               for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                                       for(channel = 0; channel < channels; channel++, sample++)
+                                                               s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
+                                       }
+                               }
+                               if(is_big_endian != is_big_endian_host_) {
+                                       unsigned char tmp;
+                                       const unsigned bytes = sample * 2;
+                                       for(byte = 0; byte < bytes; byte += 2) {
+                                               tmp = u8buffer[byte];
+                                               u8buffer[byte] = u8buffer[byte+1];
+                                               u8buffer[byte+1] = tmp;
+                                       }
+                               }
+                               bytes_to_write = 2 * sample;
+                       }
+                       else if(bps+shift == 24) {
+                               if(is_unsigned_samples) {
+                                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                               for(channel = 0; channel < channels; channel++, sample++)
+                                                       u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
+                               }
+                               else {
+                                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                               for(channel = 0; channel < channels; channel++, sample++)
+                                                       s32buffer[sample] = buffer[channel][wide_sample];
+                               }
+                               if(is_big_endian != is_big_endian_host_) {
+                                       unsigned char tmp;
+                                       const unsigned bytes = sample * 4;
+                                       for(byte = 0; byte < bytes; byte += 4) {
+                                               tmp = u8buffer[byte];
+                                               u8buffer[byte] = u8buffer[byte+3];
+                                               u8buffer[byte+3] = tmp;
+                                               tmp = u8buffer[byte+1];
+                                               u8buffer[byte+1] = u8buffer[byte+2];
+                                               u8buffer[byte+2] = tmp;
+                                       }
+                               }
+                               if(is_big_endian) {
+                                       unsigned lbyte;
+                                       const unsigned bytes = sample * 4;
+                                       for(lbyte = byte = 0; byte < bytes; ) {
+                                               byte++;
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                       }
+                               }
+                               else {
+                                       unsigned lbyte;
+                                       const unsigned bytes = sample * 4;
+                                       for(lbyte = byte = 0; byte < bytes; ) {
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                               u8buffer[lbyte++] = u8buffer[byte++];
+                                               byte++;
+                                       }
+                               }
+                               bytes_to_write = 3 * sample;
+                       }
+                       else if(bps+shift == 8) {
+                               if(is_unsigned_samples) {
+                                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                               for(channel = 0; channel < channels; channel++, sample++)
+                                                       u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80);
+                               }
+                               else {
+                                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                                               for(channel = 0; channel < channels; channel++, sample++)
+                                                       s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]);
+                               }
+                               bytes_to_write = sample;
+                       }
+                       else {
+                               FLAC__ASSERT(0);
+                               /* double protection */
+                               decoder_session->abort_flag = true;
+                               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+                       }
+               }
+       }
+       if(bytes_to_write > 0) {
+               if(flac__utils_fwrite(u8buffer, 1, bytes_to_write, fout) != bytes_to_write) {
+                       /* if a pipe closed when writing to stdout, we let it go without an error message */
+                       if(errno == EPIPE && decoder_session->fout == stdout)
+                               decoder_session->aborting_due_to_until = true;
+                       decoder_session->abort_flag = true;
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       DecoderSession *decoder_session = (DecoderSession*)client_data;
+
+       if(decoder_session->analysis_mode)
+               FLAC__stream_decoder_get_decode_position(decoder, &decoder_session->decode_position);
+
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               FLAC__uint64 skip, until;
+               decoder_session->got_stream_info = true;
+               decoder_session->has_md5sum = memcmp(metadata->data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
+               decoder_session->bps = metadata->data.stream_info.bits_per_sample;
+               decoder_session->channels = metadata->data.stream_info.channels;
+               decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
+
+               flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate);
+               FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+               skip = (FLAC__uint64)decoder_session->skip_specification->value.samples;
+
+               /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
+               if(metadata->data.stream_info.total_samples > 0 && skip >= metadata->data.stream_info.total_samples) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR trying to --skip more samples than in stream\n", decoder_session->inbasefilename);
+                       decoder_session->abort_flag = true;
+                       return;
+               }
+               else if(metadata->data.stream_info.total_samples == 0 && skip > 0) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR, can't --skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
+                       decoder_session->abort_flag = true;
+                       return;
+               }
+               FLAC__ASSERT(skip == 0 || 0 == decoder_session->cue_specification);
+               decoder_session->total_samples = metadata->data.stream_info.total_samples - skip;
+
+               /* note that we use metadata->data.stream_info.total_samples instead of decoder_session->total_samples */
+               if(!canonicalize_until_specification(decoder_session->until_specification, decoder_session->inbasefilename, decoder_session->sample_rate, skip, metadata->data.stream_info.total_samples)) {
+                       decoder_session->abort_flag = true;
+                       return;
+               }
+               FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+               until = (FLAC__uint64)decoder_session->until_specification->value.samples;
+
+               if(until > 0) {
+                       FLAC__ASSERT(decoder_session->total_samples != 0);
+                       FLAC__ASSERT(0 == decoder_session->cue_specification);
+                       decoder_session->total_samples -= (metadata->data.stream_info.total_samples - until);
+               }
+
+               if(decoder_session->bps < 4 || decoder_session->bps > 24) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 4-24\n", decoder_session->inbasefilename, decoder_session->bps);
+                       decoder_session->abort_flag = true;
+                       return;
+               }
+       }
+       else if(metadata->type == FLAC__METADATA_TYPE_CUESHEET) {
+               /* remember, at this point, decoder_session->total_samples can be 0, meaning 'unknown' */
+               if(decoder_session->total_samples == 0) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR can't use --cue when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
+                       decoder_session->abort_flag = true;
+                       return;
+               }
+
+               flac__utils_canonicalize_cue_specification(decoder_session->cue_specification, &metadata->data.cue_sheet, decoder_session->total_samples, decoder_session->skip_specification, decoder_session->until_specification);
+
+               FLAC__ASSERT(!decoder_session->skip_specification->is_relative);
+               FLAC__ASSERT(decoder_session->skip_specification->value_is_samples);
+
+               FLAC__ASSERT(!decoder_session->until_specification->is_relative);
+               FLAC__ASSERT(decoder_session->until_specification->value_is_samples);
+
+               FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+               FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0);
+               FLAC__ASSERT((FLAC__uint64)decoder_session->until_specification->value.samples <= decoder_session->total_samples);
+               FLAC__ASSERT(decoder_session->skip_specification->value.samples <= decoder_session->until_specification->value.samples);
+
+               decoder_session->total_samples = decoder_session->until_specification->value.samples - decoder_session->skip_specification->value.samples;
+       }
+       else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+               if (decoder_session->replaygain.spec.apply) {
+                       double reference, gain, peak;
+                       if (!(decoder_session->replaygain.apply = grabbag__replaygain_load_from_vorbiscomment(metadata, decoder_session->replaygain.spec.use_album_gain, /*strict=*/false, &reference, &gain, &peak))) {
+                               flac__utils_printf(stderr, 1, "%s: WARNING: can't get %s (or even %s) ReplayGain tags\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", decoder_session->replaygain.spec.use_album_gain? "track":"album");
+                               if(decoder_session->treat_warnings_as_errors) {
+                                       decoder_session->abort_flag = true;
+                                       return;
+                               }
+                       }
+                       else {
+                               const char *ls[] = { "no", "peak", "hard" };
+                               const char *ns[] = { "no", "low", "medium", "high" };
+                               decoder_session->replaygain.scale = grabbag__replaygain_compute_scale_factor(peak, gain, decoder_session->replaygain.spec.preamp, decoder_session->replaygain.spec.limiter == RGSS_LIMIT__PEAK);
+                               FLAC__ASSERT(decoder_session->bps > 0 && decoder_session->bps <= 32);
+                               FLAC__replaygain_synthesis__init_dither_context(&decoder_session->replaygain.dither_context, decoder_session->bps, decoder_session->replaygain.spec.noise_shaping);
+                               flac__utils_printf(stderr, 1, "%s: INFO: applying %s ReplayGain (gain=%0.2fdB+preamp=%0.1fdB, %s noise shaping, %s limiting) to output\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", gain, decoder_session->replaygain.spec.preamp, ns[decoder_session->replaygain.spec.noise_shaping], ls[decoder_session->replaygain.spec.limiter]);
+                               flac__utils_printf(stderr, 1, "%s: WARNING: applying ReplayGain is not lossless\n", decoder_session->inbasefilename);
+                               /* don't check if(decoder_session->treat_warnings_as_errors) because the user explicitly asked for it */
+                       }
+               }
+               (void)flac__utils_get_channel_mask_tag(metadata, &decoder_session->channel_mask);
+       }
+}
+
+void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       DecoderSession *decoder_session = (DecoderSession*)client_data;
+       (void)decoder;
+       flac__utils_printf(stderr, 1, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]);
+       if(!decoder_session->continue_through_decode_errors) {
+               decoder_session->abort_flag = true;
+               if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+                       decoder_session->aborting_due_to_unparseable = true;
+       }
+}
+
+void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status)
+{
+       const int ilen = strlen(d->inbasefilename) + 1;
+
+       flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message);
+
+       flac__utils_printf(stderr, 1, "%*s init status = %s\n", ilen, "", FLAC__StreamDecoderInitStatusString[init_status]);
+
+       /* print out some more info for some errors: */
+       if (init_status == FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE) {
+               flac__utils_printf(stderr, 1,
+                       "\n"
+                       "An error occurred opening the input file; it is likely that it does not exist\n"
+                       "or is not readable.\n"
+               );
+       }
+}
+
+void print_error_with_state(const DecoderSession *d, const char *message)
+{
+       const int ilen = strlen(d->inbasefilename) + 1;
+
+       flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message);
+       flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", FLAC__stream_decoder_get_resolved_state_string(d->decoder));
+
+       /* print out some more info for some errors: */
+       if (d->aborting_due_to_unparseable) {
+               flac__utils_printf(stderr, 1,
+                       "\n"
+                       "The FLAC stream may have been created by a more advanced encoder.  Try\n"
+                       "  metaflac --show-vendor-tag %s\n"
+                       "If the version number is greater than %s, this decoder is probably\n"
+                       "not able to decode the file.  If the version number is not, the file\n"
+                       "may be corrupted, or you may have found a bug.  In this case please\n"
+                       "submit a bug report to\n"
+                       "    http://sourceforge.net/bugs/?func=addbug&group_id=13478\n"
+                       "Make sure to use the \"Monitor\" feature to monitor the bug status.\n",
+                       d->inbasefilename, FLAC__VERSION_STRING
+               );
+       }
+}
+
+void print_stats(const DecoderSession *decoder_session)
+{
+       if(flac__utils_verbosity_ >= 2) {
+#if defined _MSC_VER || defined __MINGW32__
+               /* with MSVC you have to spoon feed it the casting */
+               const double progress = (double)(FLAC__int64)decoder_session->samples_processed / (double)(FLAC__int64)decoder_session->total_samples * 100.0;
+#else
+               const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
+#endif
+               if(decoder_session->total_samples > 0) {
+                       fprintf(stderr, "\r%s: %s%u%% complete",
+                               decoder_session->inbasefilename,
+                               decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
+                               (unsigned)floor(progress + 0.5)
+                       );
+               }
+               else {
+                       fprintf(stderr, "\r%s: %s %u samples",
+                               decoder_session->inbasefilename,
+                               decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote",
+                               (unsigned)decoder_session->samples_processed
+                       );
+               }
+       }
+}
diff --git a/src/flac/decode.h b/src/flac/decode.h
new file mode 100644 (file)
index 0000000..2ab9deb
--- /dev/null
@@ -0,0 +1,74 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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__decode_h
+#define flac__decode_h
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "analyze.h"
+#include "foreign_metadata.h"
+#include "utils.h"
+#include "share/replaygain_synthesis.h"
+
+
+typedef struct {
+       FLAC__bool apply;
+       FLAC__bool use_album_gain; /* false => use track gain */
+       enum { RGSS_LIMIT__NONE, RGSS_LIMIT__PEAK, RGSS_LIMIT__HARD} limiter;
+       NoiseShaping noise_shaping;
+       double preamp;
+} replaygain_synthesis_spec_t;
+
+typedef struct {
+       FLAC__bool treat_warnings_as_errors;
+       FLAC__bool continue_through_decode_errors;
+       replaygain_synthesis_spec_t replaygain_synthesis_spec;
+#if FLAC__HAS_OGG
+       FLAC__bool is_ogg;
+       FLAC__bool use_first_serial_number;
+       long serial_number;
+#endif
+       utils__SkipUntilSpecification skip_specification;
+       utils__SkipUntilSpecification until_specification;
+       FLAC__bool has_cue_specification;
+       utils__CueSpecification cue_specification;
+       FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+} decode_options_t;
+
+/* used for AIFF also */
+typedef struct {
+       decode_options_t common;
+       foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+} wav_decode_options_t;
+
+typedef struct {
+       decode_options_t common;
+
+       FLAC__bool is_big_endian;
+       FLAC__bool is_unsigned_samples;
+} raw_decode_options_t;
+
+/* outfile == 0 => test only */
+int flac__decode_aiff(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options);
+int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options);
+int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options);
+
+#endif
diff --git a/src/flac/encode.c b/src/flac/encode.c
new file mode 100644 (file)
index 0000000..8d24349
--- /dev/null
@@ -0,0 +1,2936 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include <errno.h>
+#include <limits.h> /* for LONG_MAX */
+#include <math.h> /* for floor() */
+#include <stdio.h> /* for FILE etc. */
+#include <stdlib.h> /* for malloc */
+#include <string.h> /* for strcmp(), strerror() */
+#include "FLAC/all.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "encode.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* this MUST be >= 588 so that sector aligning can take place with one read */
+#define CHUNK_OF_SAMPLES 2048
+
+typedef struct {
+#if FLAC__HAS_OGG
+       FLAC__bool use_ogg;
+#endif
+       FLAC__bool verify;
+       FLAC__bool is_stdout;
+       FLAC__bool outputfile_opened; /* true if we successfully opened the output file and we want it to be deleted if there is an error */
+       const char *inbasefilename;
+       const char *infilename;
+       const char *outfilename;
+
+       FLAC__uint64 skip;
+       FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */
+       FLAC__bool treat_warnings_as_errors;
+       FLAC__bool continue_through_decode_errors;
+       FLAC__bool replay_gain;
+       unsigned channels;
+       unsigned bits_per_sample;
+       unsigned sample_rate;
+       FLAC__uint64 unencoded_size;
+       FLAC__uint64 total_samples_to_encode;
+       FLAC__uint64 bytes_written;
+       FLAC__uint64 samples_written;
+       unsigned stats_mask;
+
+       FLAC__StreamEncoder *encoder;
+
+       FILE *fin;
+       FLAC__StreamMetadata *seek_table_template;
+} EncoderSession;
+
+/* this is data attached to the FLAC decoder when encoding from a FLAC file */
+typedef struct {
+       EncoderSession *encoder_session;
+       off_t filesize;
+       const FLAC__byte *lookahead;
+       unsigned lookahead_length;
+       size_t num_metadata_blocks;
+       FLAC__StreamMetadata *metadata_blocks[1024]; /*@@@ BAD MAGIC number */
+       FLAC__uint64 samples_left_to_process;
+       FLAC__bool fatal_error;
+} FLACDecoderData;
+
+const int FLAC_ENCODE__DEFAULT_PADDING = 8192;
+
+static FLAC__bool is_big_endian_host_;
+
+static unsigned char ucbuffer_[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*((FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE+7)/8)];
+static signed char *scbuffer_ = (signed char *)ucbuffer_;
+static FLAC__uint16 *usbuffer_ = (FLAC__uint16 *)ucbuffer_;
+static FLAC__int16 *ssbuffer_ = (FLAC__int16 *)ucbuffer_;
+
+static FLAC__int32 in_[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES];
+static FLAC__int32 *input_[FLAC__MAX_CHANNELS];
+
+
+/*
+ * unpublished debug routines from the FLAC libs
+ */
+extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/*
+ * local routines
+ */
+static FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC__bool verify, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FILE *infile, const char *infilename, const char *outfilename);
+static void EncoderSession_destroy(EncoderSession *e);
+static int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata);
+static int EncoderSession_finish_error(EncoderSession *e);
+static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, FLAC__uint32 channel_mask, unsigned channels, unsigned bps, unsigned sample_rate, const foreign_metadata_t *foreign_metadata, FLACDecoderData *flac_decoder_data);
+static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], unsigned samples);
+static FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e);
+static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
+static FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, unsigned num_metadata);
+static FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned shift, size_t *channel_map);
+static void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+static FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
+static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors);
+static void print_stats(const EncoderSession *encoder_session);
+static void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status);
+static void print_error_with_state(const EncoderSession *e, const char *message);
+static void print_verify_error(EncoderSession *e);
+static FLAC__bool read_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_big_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_big_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset);
+static unsigned count_channel_mask_bits(FLAC__uint32 mask);
+#if 0
+static FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, unsigned channels);
+#endif
+
+/*
+ * public routines
+ */
+int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options, FLAC__bool is_aifc)
+{
+       EncoderSession encoder_session;
+       FLAC__uint16 x;
+       FLAC__uint32 xx;
+       unsigned int channels= 0U, bps= 0U, shift= 0U, sample_rate= 0U, sample_frames= 0U;
+       size_t channel_map[FLAC__MAX_CHANNELS];
+       FLAC__bool got_comm_chunk= false, got_ssnd_chunk= false;
+       int info_align_carry= -1, info_align_zero= -1;
+       FLAC__bool is_big_endian_pcm = true;
+
+       (void)infilesize; /* silence compiler warning about unused parameter */
+       (void)lookahead; /* silence compiler warning about unused parameter */
+       (void)lookahead_length; /* silence compiler warning about unused parameter */
+
+       if(!
+               EncoderSession_construct(
+                       &encoder_session,
+#if FLAC__HAS_OGG
+                       options.common.use_ogg,
+#else
+                       /*use_ogg=*/false,
+#endif
+                       options.common.verify,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       infile,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       /* initialize default channel map that preserves channel order */
+       {
+               size_t i;
+               for(i = 0; i < sizeof(channel_map)/sizeof(channel_map[0]); i++)
+                       channel_map[i] = i;
+       }
+
+       if(options.foreign_metadata) {
+               const char *error;
+               if(!flac__foreign_metadata_read_from_aiff(options.foreign_metadata, infilename, &error)) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error);
+                       return EncoderSession_finish_error(&encoder_session);
+               }
+       }
+
+       /* lookahead[] already has "FORMxxxxAIFF", do sub-chunks */
+
+       while(1) {
+               size_t c= 0U;
+               char chunk_id[5] = { '\0', '\0', '\0', '\0', '\0' }; /* one extra byte for terminating NUL so we can also treat it like a C string */
+
+               /* chunk identifier; really conservative about behavior of fread() and feof() */
+               if(feof(infile) || ((c= fread(chunk_id, 1U, 4U, infile)), c==0U && feof(infile)))
+                       break;
+               else if(c<4U || feof(infile)) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", encoder_session.inbasefilename);
+                       return EncoderSession_finish_error(&encoder_session);
+               }
+
+               if(got_comm_chunk==false && !memcmp(chunk_id, "COMM", 4)) { /* common chunk */
+                       unsigned long skip;
+                       const FLAC__uint32 minimum_comm_size = (is_aifc? 22 : 18);
+
+                       /* COMM chunk size */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else if(xx<minimum_comm_size) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: non-standard %s 'COMM' chunk has length = %u\n", encoder_session.inbasefilename, is_aifc? "AIFF-C" : "AIFF", (unsigned int)xx);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(!is_aifc && xx!=minimum_comm_size) {
+                               flac__utils_printf(stderr, 1, "%s: WARNING: non-standard %s 'COMM' chunk has length = %u, expected %u\n", encoder_session.inbasefilename, is_aifc? "AIFF-C" : "AIFF", (unsigned int)xx, minimum_comm_size);
+                               if(encoder_session.treat_warnings_as_errors)
+                                       return EncoderSession_finish_error(&encoder_session);
+                       }
+                       skip= (xx-minimum_comm_size)+(xx & 1U);
+
+                       /* number of channels */
+                       if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else if(x==0U || x>FLAC__MAX_CHANNELS) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u\n", encoder_session.inbasefilename, (unsigned int)x);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(x>2U && !options.common.channel_map_none) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u for AIFF\n", encoder_session.inbasefilename, (unsigned int)x);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && x!=2U) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       channels= x;
+
+                       /* number of sample frames */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       sample_frames= xx;
+
+                       /* bits per sample */
+                       if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else if(x<4U || x>24U) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, (unsigned int)x);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && x!=16U) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits-per-sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       bps= x;
+                       shift= (bps%8)? 8-(bps%8) : 0; /* SSND data is always byte-aligned, left-justified but format_input() will double-check */
+                       bps+= shift;
+
+                       /* sample rate */
+                       if(!read_sane_extended(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else if(!FLAC__format_sample_rate_is_valid(xx)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, (unsigned int)xx);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && xx!=44100U) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)xx);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       sample_rate= xx;
+
+                       /* check compression type for AIFF-C */
+                       if(is_aifc) {
+                               if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                                       return EncoderSession_finish_error(&encoder_session);
+                               if(xx == 0x736F7774) /* "sowt" */
+                                       is_big_endian_pcm = false;
+                               else if(xx == 0x4E4F4E45) /* "NONE" */
+                                       ; /* nothing to do, we already default to big-endian */
+                               else {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", encoder_session.inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8));
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       /* set channel mapping */
+                       /* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */
+                       /* front left, front right, center, LFE, back left, back right, surround left, surround right */
+                       /* specs say the channel ordering is:
+                        *                             1     2   3   4   5   6
+                        * ___________________________________________________
+                        * 2         stereo            l     r
+                        * 3                           l     r   c
+                        * 4                           l     c   r   S
+                        * quad (ambiguous with 4ch)  Fl    Fr   Bl  Br
+                        * 5                          Fl     Fr  Fc  Sl  Sr
+                        * 6                           l     lc  c   r   rc  S
+                        * l:left r:right c:center Fl:front-left Fr:front-right Bl:back-left Br:back-right Lc:left-center Rc:right-center S:surround
+                        * so we only have unambiguous mappings for 2, 3, and 5 channels
+                        */
+                       if(
+                               options.common.channel_map_none ||
+                               channels == 1 || /* 1 channel: (mono) */
+                               channels == 2 || /* 2 channels: left, right */
+                               channels == 3 || /* 3 channels: left, right, center */
+                               channels == 5    /* 5 channels: front left, front right, center, surround left, surround right */
+                       ) {
+                               /* keep default channel order */
+                       }
+                       else {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u for AIFF\n", encoder_session.inbasefilename, channels);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* skip any extra data in the COMM chunk */
+                       if(!fskip_ahead(infile, skip)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra COMM data\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /*
+                        * now that we know the sample rate, canonicalize the
+                        * --skip string to a number of samples:
+                        */
+                       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate);
+                       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+                       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+
+                       got_comm_chunk= true;
+               }
+               else if(got_ssnd_chunk==false && !memcmp(chunk_id, "SSND", 4)) { /* sound data chunk */
+                       unsigned int offset= 0U, block_size= 0U, align_remainder= 0U, data_bytes;
+                       const size_t bytes_per_frame= channels*(bps>>3);
+                       FLAC__uint64 total_samples_in_input, trim = 0;
+                       FLAC__bool pad= false;
+
+                       if(got_comm_chunk==false) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* SSND chunk size */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       if(options.common.ignore_chunk_sizes) {
+                               FLAC__ASSERT(!options.common.sector_align);
+                               data_bytes = (unsigned)(-(int)bytes_per_frame); /* max out data_bytes; we'll use EOF as signal to stop reading */
+                       }
+                       else {
+                               data_bytes= xx;
+                               data_bytes-= 8U; /* discount the offset and block size fields */
+                       }
+                       pad= (data_bytes & 1U) ? true : false;
+
+                       /* offset */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       offset= xx;
+                       data_bytes-= offset;
+
+                       /* block size */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else if(xx!=0U) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: block size is %u; must be 0\n", encoder_session.inbasefilename, (unsigned int)xx);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       block_size= xx;
+
+                       /* skip any SSND offset bytes */
+                       FLAC__ASSERT(offset<=LONG_MAX);
+                       if(!fskip_ahead(infile, offset)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: skipping offset in SSND chunk\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       if(data_bytes!=(sample_frames*bytes_per_frame)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: SSND chunk size inconsistent with sample frame count\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */
+                       FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0);
+                       total_samples_in_input = data_bytes / bytes_per_frame + *options.common.align_reservoir_samples;
+
+                       /*
+                        * now that we know the input size, canonicalize the
+                        * --until string to an absolute sample number:
+                        */
+                       if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, sample_rate, encoder_session.skip, total_samples_in_input))
+                               return EncoderSession_finish_error(&encoder_session);
+                       encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0);
+
+                       if(encoder_session.skip>0U) {
+                               if(!fskip_ahead(infile, encoder_session.skip*bytes_per_frame)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       data_bytes-= (unsigned int)encoder_session.skip*bytes_per_frame; /*@@@ WATCHOUT: 4GB limit */
+                       if(options.common.ignore_chunk_sizes) {
+                               encoder_session.total_samples_to_encode= 0;
+                               flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+                               FLAC__ASSERT(0 == encoder_session.until);
+                       }
+                       else {
+                               encoder_session.total_samples_to_encode= total_samples_in_input - encoder_session.skip;
+                       }
+                       if(encoder_session.until > 0) {
+                               trim = total_samples_in_input - encoder_session.until;
+                               FLAC__ASSERT(total_samples_in_input > 0);
+                               FLAC__ASSERT(!options.common.sector_align);
+                               data_bytes-= (unsigned int)trim*bytes_per_frame;
+                               encoder_session.total_samples_to_encode-= trim;
+                       }
+                       if(options.common.sector_align) {
+                               align_remainder= (unsigned int)(encoder_session.total_samples_to_encode % 588U);
+                               if(options.common.is_last_file)
+                                       encoder_session.total_samples_to_encode+= (588U-align_remainder); /* will pad with zeroes */
+                               else
+                                       encoder_session.total_samples_to_encode-= align_remainder; /* will stop short and carry over to next file */
+                       }
+
+                       /* +54 for the size of the AIFF headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+                       encoder_session.unencoded_size= encoder_session.total_samples_to_encode*bytes_per_frame+54;
+
+                       if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, channels, bps-shift, sample_rate, options.foreign_metadata, /*flac_decoder_data=*/0))
+                               return EncoderSession_finish_error(&encoder_session);
+
+                       /* first do any samples in the reservoir */
+                       if(options.common.sector_align && *options.common.align_reservoir_samples>0U) {
+
+                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) {
+                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       /* decrement the data_bytes counter if we need to align the file */
+                       if(options.common.sector_align) {
+                               if(options.common.is_last_file)
+                                       *options.common.align_reservoir_samples= 0U;
+                               else {
+                                       *options.common.align_reservoir_samples= align_remainder;
+                                       data_bytes-= (*options.common.align_reservoir_samples)*bytes_per_frame;
+                               }
+                       }
+
+                       /* now do from the file */
+                       while(data_bytes>0) {
+                               size_t bytes_read= fread(ucbuffer_, 1U, min(data_bytes, CHUNK_OF_SAMPLES*bytes_per_frame), infile);
+
+                               if(bytes_read==0U) {
+                                       if(ferror(infile)) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       else if(feof(infile)) {
+                                               if(options.common.ignore_chunk_sizes) {
+                                                       flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written);
+                                               }
+                                               else {
+                                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+                                                       if(encoder_session.treat_warnings_as_errors)
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               data_bytes= 0;
+                                       }
+                               }
+                               else {
+                                       if(bytes_read % bytes_per_frame != 0U) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       else {
+                                               unsigned int frames= bytes_read/bytes_per_frame;
+                                               if(!format_input(input_, frames, is_big_endian_pcm, /*is_unsigned_samples=*/false, channels, bps, shift, channel_map))
+                                                       return EncoderSession_finish_error(&encoder_session);
+
+                                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)input_, frames)) {
+                                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               else
+                                                       data_bytes-= bytes_read;
+                                       }
+                               }
+                       }
+
+                       if(trim>0) {
+                               FLAC__ASSERT(!options.common.sector_align);
+                               if(!fskip_ahead(infile, trim*bytes_per_frame)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       /* now read unaligned samples into reservoir or pad with zeroes if necessary */
+                       if(options.common.sector_align) {
+                               if(options.common.is_last_file) {
+                                       unsigned int pad_frames= 588U-align_remainder;
+
+                                       if(pad_frames<588U) {
+                                               unsigned int i;
+
+                                               info_align_zero= pad_frames;
+                                               for(i= 0U; i<channels; ++i)
+                                                       memset(input_[i], 0, sizeof(input_[0][0])*pad_frames);
+
+                                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)input_, pad_frames)) {
+                                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                       }
+                               }
+                               else {
+                                       if(*options.common.align_reservoir_samples > 0) {
+                                               size_t bytes_read= fread(ucbuffer_, 1U, (*options.common.align_reservoir_samples)*bytes_per_frame, infile);
+
+                                               FLAC__ASSERT(CHUNK_OF_SAMPLES>=588U);
+                                               if(bytes_read==0U && ferror(infile)) {
+                                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_frame) {
+                                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned int)bytes_read, (unsigned int)encoder_session.total_samples_to_encode, (unsigned int)encoder_session.samples_written);
+                                                       if(encoder_session.treat_warnings_as_errors)
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               else {
+                                                       info_align_carry= *options.common.align_reservoir_samples;
+                                                       if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, is_big_endian_pcm, /*is_unsigned_samples=*/false, channels, bps, shift, channel_map))
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if(pad==true) {
+                               unsigned char tmp;
+
+                               if(fread(&tmp, 1U, 1U, infile)<1U) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read of SSND pad byte\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       got_ssnd_chunk= true;
+               }
+               else { /* other chunk */
+                       if(!options.foreign_metadata) {
+                               if(!memcmp(chunk_id, "COMM", 4))
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'COMM' chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename);
+                               else if(!memcmp(chunk_id, "SSND", 4))
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'SSND' chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename);
+                               else if(!options.foreign_metadata)
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename, chunk_id);
+                               if(encoder_session.treat_warnings_as_errors)
+                                       return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* chunk size */
+                       if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else {
+                               unsigned long skip= xx+(xx & 1U);
+
+                               FLAC__ASSERT(skip<=LONG_MAX);
+                               if(!fskip_ahead(infile, skip)) {
+                                       fprintf(stderr, "%s: ERROR during read while skipping over unknown chunk\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+               }
+       }
+
+       if(got_ssnd_chunk==false && sample_frames!=0U) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: missing SSND chunk\n", encoder_session.inbasefilename);
+               return EncoderSession_finish_error(&encoder_session);
+       }
+
+       return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, options.foreign_metadata);
+}
+
+int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options)
+{
+       EncoderSession encoder_session;
+       FLAC__bool is_unsigned_samples = false;
+       unsigned channels = 0, bps = 0, sample_rate = 0, shift = 0;
+       size_t bytes_read;
+       size_t channel_map[FLAC__MAX_CHANNELS];
+       FLAC__uint16 x, format; /* format is the wFormatTag word from the 'fmt ' chunk */
+       FLAC__uint32 xx, channel_mask = 0;
+       FLAC__bool got_fmt_chunk = false, got_data_chunk = false;
+       unsigned align_remainder = 0;
+       int info_align_carry = -1, info_align_zero = -1;
+
+       (void)infilesize;
+       (void)lookahead;
+       (void)lookahead_length;
+
+       if(!
+               EncoderSession_construct(
+                       &encoder_session,
+#if FLAC__HAS_OGG
+                       options.common.use_ogg,
+#else
+                       /*use_ogg=*/false,
+#endif
+                       options.common.verify,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       infile,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       /* initialize default channel map that preserves channel order */
+       {
+               size_t i;
+               for(i = 0; i < sizeof(channel_map)/sizeof(channel_map[0]); i++)
+                       channel_map[i] = i;
+       }
+
+       if(options.foreign_metadata) {
+               const char *error;
+               if(!flac__foreign_metadata_read_from_wave(options.foreign_metadata, infilename, &error)) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error);
+                       return EncoderSession_finish_error(&encoder_session);
+               }
+       }
+
+       /*
+        * lookahead[] already has "RIFFxxxxWAVE", do sub-chunks
+        */
+       while(!feof(infile)) {
+               if(!read_little_endian_uint32(infile, &xx, true, encoder_session.inbasefilename))
+                       return EncoderSession_finish_error(&encoder_session);
+               if(feof(infile))
+                       break;
+               if(xx == 0x20746d66 && !got_fmt_chunk) { /* "fmt " */
+                       unsigned block_align, data_bytes;
+
+                       /* see
+                        *   http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
+                        *   http://windowssdk.msdn.microsoft.com/en-us/library/ms713497.aspx
+                        *   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/audio_r/hh/Audio_r/aud-prop_d40f094e-44f9-4baa-8a15-03e4fb369501.xml.asp
+                        *
+                        * WAVEFORMAT is
+                        * 4 byte: subchunk size
+                        * 2 byte: format type: 1 for WAVE_FORMAT_PCM, 65534 for WAVE_FORMAT_EXTENSIBLE
+                        * 2 byte: # channels
+                        * 4 byte: sample rate (Hz)
+                        * 4 byte: avg bytes per sec
+                        * 2 byte: block align
+                        * 2 byte: bits per sample (not necessarily all significant)
+                        * WAVEFORMATEX adds
+                        * 2 byte: extension size in bytes (usually 0 for WAVEFORMATEX and 22 for WAVEFORMATEXTENSIBLE with PCM)
+                        * WAVEFORMATEXTENSIBLE adds
+                        * 2 byte: valid bits per sample
+                        * 4 byte: channel mask
+                        * 16 byte: subformat GUID, first 2 bytes have format type, 1 being PCM
+                        *
+                        * Current spec says WAVEFORMATEX with PCM must have bps == 8 or 16, or any multiple of 8 for WAVEFORMATEXTENSIBLE.
+                        * Lots of old broken WAVEs/apps have don't follow it, e.g. 20 bps but a block align of 3/6 for mono/stereo.
+                        *
+                        * Block align for WAVE_FORMAT_PCM or WAVE_FORMAT_EXTENSIBLE is also supposed to be channels*bps/8
+                        *
+                        * If the channel mask has more set bits than # of channels, the extra MSBs are ignored.
+                        * If the channel mask has less set bits than # of channels, the extra channels are unassigned to any speaker.
+                        *
+                        * Data is supposed to be unsigned for bps <= 8 else signed.
+                        */
+
+                       /* fmt sub-chunk size */
+                       if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       data_bytes = xx;
+                       if(data_bytes < 16) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: found non-standard 'fmt ' sub-chunk which has length = %u\n", encoder_session.inbasefilename, data_bytes);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       /* format code */
+                       if(!read_little_endian_uint16(infile, &format, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       if(format != 1 /*WAVE_FORMAT_PCM*/ && format != 65534 /*WAVE_FORMAT_EXTENSIBLE*/) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported format type %u\n", encoder_session.inbasefilename, (unsigned)format);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       /* number of channels */
+                       if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       channels = (unsigned)x;
+                       if(channels == 0 || channels > FLAC__MAX_CHANNELS) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u\n", encoder_session.inbasefilename, channels);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && channels != 2) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, channels);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       /* sample rate */
+                       if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       sample_rate = xx;
+                       if(!FLAC__format_sample_rate_is_valid(sample_rate)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, sample_rate);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && sample_rate != 44100) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, sample_rate);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       /* avg bytes per second (ignored) */
+                       if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       /* block align */
+                       if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       block_align = (unsigned)x;
+                       /* bits per sample */
+                       if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       bps = (unsigned)x;
+                       is_unsigned_samples = (bps <= 8);
+                       if(format == 1) {
+                               if(bps != 8 && bps != 16) {
+                                       if(bps == 24 || bps == 32) {
+                                               /* let these slide with a warning since they're unambiguous */
+                                               flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file has format type %u but bits-per-sample=%u\n", encoder_session.inbasefilename, (unsigned)format, bps);
+                                               if(encoder_session.treat_warnings_as_errors)
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       else {
+                                               /* @@@ we could add an option to specify left- or right-justified blocks so we knew how to set 'shift' */
+                                               flac__utils_printf(stderr, 1, "%s: ERROR: legacy WAVE file has format type %u but bits-per-sample=%u\n", encoder_session.inbasefilename, (unsigned)format, bps);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                               }
+#if 0 /* @@@ reinstate once we can get an answer about whether the samples are left- or right-justified */
+                               if((bps+7)/8 * channels == block_align) {
+                                       if(bps % 8) {
+                                               /* assume legacy file is byte aligned with some LSBs zero; this is double-checked in format_input() */
+                                               flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", encoder_session.inbasefilename, (unsigned)format, block_align, bps, channels);
+                                               if(encoder_session.treat_warnings_as_errors)
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               shift = 8 - (bps % 8);
+                                               bps += shift;
+                                       }
+                                       else
+                                               shift = 0;
+                               }
+                               else {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: illegal WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", encoder_session.inbasefilename, (unsigned)format, block_align, bps, channels);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+#else
+                               shift = 0;
+#endif
+                               if(channels > 2 && !options.common.channel_map_none) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: WAVE has >2 channels but is not WAVE_FORMAT_EXTENSIBLE; cannot assign channels\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               FLAC__ASSERT(data_bytes >= 16);
+                               data_bytes -= 16;
+                       }
+                       else {
+                               if(data_bytes < 40) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with size %u\n", encoder_session.inbasefilename, data_bytes);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               /* cbSize */
+                               if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                                       return EncoderSession_finish_error(&encoder_session);
+                               if(x < 22) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with cbSize %u\n", encoder_session.inbasefilename, (unsigned)x);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               /* valid bps */
+                               if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                                       return EncoderSession_finish_error(&encoder_session);
+                               if((unsigned)x > bps) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with wValidBitsPerSample (%u) > wBitsPerSample (%u)\n", encoder_session.inbasefilename, (unsigned)x, bps);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               shift = bps - (unsigned)x;
+                               /* channel mask */
+                               if(!read_little_endian_uint32(infile, &channel_mask, false, encoder_session.inbasefilename))
+                                       return EncoderSession_finish_error(&encoder_session);
+                               /* for mono/stereo and unassigned channels, we fake the mask */
+                               if(channel_mask == 0) {
+                                       if(channels == 1)
+                                               channel_mask = 0x0001;
+                                       else if(channels == 2)
+                                               channel_mask = 0x0003;
+                               }
+                               /* set channel mapping */
+                               /* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */
+                               /* front left, front right, center, LFE, back left, back right, surround left, surround right */
+                               /* the default mapping is sufficient for 1-6 channels and 7-8 are currently unspecified anyway */
+#if 0
+                               /* @@@ example for dolby/vorbis order, for reference later in case it becomes important */
+                               if(
+                                       options.common.channel_map_none ||
+                                       channel_mask == 0x0001 || /* 1 channel: (mono) */
+                                       channel_mask == 0x0003 || /* 2 channels: front left, front right */
+                                       channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */
+                                       channel_mask == 0x0603    /* 4 channels: front left, front right, side left, side right */
+                               ) {
+                                       /* keep default channel order */
+                               }
+                               else if(
+                                       channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */
+                                       channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */
+                                       channel_mask == 0x0607    /* 5 channels: front left, front right, front center, side left, side right */
+                               ) {
+                                       /* to dolby order: front left, center, front right [, surround left, surround right ] */
+                                       channel_map[1] = 2;
+                                       channel_map[2] = 1;
+                               }
+                               else if(
+                                       channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */
+                                       channel_mask == 0x060f    /* 6 channels: front left, front right, front center, LFE, side left, side right */
+                               ) {
+                                       /* to dolby order: front left, center, front right, surround left, surround right, LFE */
+                                       channel_map[1] = 2;
+                                       channel_map[2] = 1;
+                                       channel_map[3] = 5;
+                                       channel_map[4] = 3;
+                                       channel_map[5] = 4;
+                               }
+#else
+                               if(
+                                       options.common.channel_map_none ||
+                                       channel_mask == 0x0001 || /* 1 channel: (mono) */
+                                       channel_mask == 0x0003 || /* 2 channels: front left, front right */
+                                       channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */
+                                       channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */
+                                       channel_mask == 0x0603 || /* 4 channels: front left, front right, side left, side right */
+                                       channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */
+                                       channel_mask == 0x0607 || /* 5 channels: front left, front right, front center, side left, side right */
+                                       channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */
+                                       channel_mask == 0x060f    /* 6 channels: front left, front right, front center, LFE, side left, side right */
+                               ) {
+                                       /* keep default channel order */
+                               }
+#endif
+                               else {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk with unsupported channel mask=0x%04X\n", encoder_session.inbasefilename, (unsigned)channel_mask);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               if(!options.common.channel_map_none) {
+                                       if(count_channel_mask_bits(channel_mask) < channels) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has unassigned channels (#channels=%u)\n", encoder_session.inbasefilename, (unsigned)channel_mask, channels);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+#if 0
+                                       /* supporting this is too difficult with channel mapping; e.g. what if mask is 0x003f but #channels=4?
+                                        * there would be holes in the order that would have to be filled in, or the mask would have to be
+                                        * limited and the logic above rerun to see if it still fits into the FLAC mapping.
+                                        */
+                                       else if(count_channel_mask_bits(channel_mask) > channels)
+                                               channel_mask = limit_channel_mask(channel_mask, channels);
+#else
+                                       else if(count_channel_mask_bits(channel_mask) > channels) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has extra bits for non-existant channels (#channels=%u)\n", encoder_session.inbasefilename, (unsigned)channel_mask, channels);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+#endif
+                               }
+                               /* first part of GUID */
+                               if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
+                                       return EncoderSession_finish_error(&encoder_session);
+                               if(x != 1) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: unsupported WAVEFORMATEXTENSIBLE chunk with non-PCM format %u\n", encoder_session.inbasefilename, (unsigned)x);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               data_bytes -= 26;
+                       }
+
+                       if(bps-shift < 4 || bps-shift > 24) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, bps-shift);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else if(options.common.sector_align && bps-shift != 16) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits-per-sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, bps-shift);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* skip any extra data in the fmt sub-chunk */
+                       if(!fskip_ahead(infile, data_bytes)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'fmt' data\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /*
+                        * now that we know the sample rate, canonicalize the
+                        * --skip string to a number of samples:
+                        */
+                       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate);
+                       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+                       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+
+                       got_fmt_chunk = true;
+               }
+               else if(xx == 0x61746164 && !got_data_chunk && got_fmt_chunk) { /* "data" */
+                       FLAC__uint64 total_samples_in_input, trim = 0;
+                       FLAC__bool pad = false;
+                       const size_t bytes_per_wide_sample = channels * (bps >> 3);
+                       unsigned data_bytes;
+
+                       /* data size */
+                       if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       if(options.common.ignore_chunk_sizes) {
+                               FLAC__ASSERT(!options.common.sector_align);
+                               data_bytes = (unsigned)(-(int)bytes_per_wide_sample); /* max out data_bytes; we'll use EOF as signal to stop reading */
+                       }
+                       else {
+                               data_bytes = xx;
+                               if(0 == data_bytes) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: 'data' subchunk has size of 0\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+                       pad = (data_bytes & 1U) ? true : false;
+
+                       /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */
+                       FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0);
+                       total_samples_in_input = data_bytes / bytes_per_wide_sample + *options.common.align_reservoir_samples;
+
+                       /*
+                        * now that we know the input size, canonicalize the
+                        * --until string to an absolute sample number:
+                        */
+                       if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, sample_rate, encoder_session.skip, total_samples_in_input))
+                               return EncoderSession_finish_error(&encoder_session);
+                       encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0);
+
+                       if(encoder_session.skip > 0) {
+                               if(!fskip_ahead(infile, encoder_session.skip * bytes_per_wide_sample)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       data_bytes -= (unsigned)encoder_session.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
+                       if(options.common.ignore_chunk_sizes) {
+                               encoder_session.total_samples_to_encode = 0;
+                               flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+                               FLAC__ASSERT(0 == encoder_session.until);
+                       }
+                       else {
+                               encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip;
+                       }
+                       if(encoder_session.until > 0) {
+                               trim = total_samples_in_input - encoder_session.until;
+                               FLAC__ASSERT(total_samples_in_input > 0);
+                               FLAC__ASSERT(!options.common.sector_align);
+                               data_bytes -= (unsigned int)trim * bytes_per_wide_sample;
+                               encoder_session.total_samples_to_encode -= trim;
+                       }
+                       if(options.common.sector_align) {
+                               align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
+                               if(options.common.is_last_file)
+                                       encoder_session.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */
+                               else
+                                       encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
+                       }
+
+                       /* +44 for the size of the WAV headers; this is just an estimate for the progress indicator and doesn't need to be exact */
+                       encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample + 44;
+
+                       if(!EncoderSession_init_encoder(&encoder_session, options.common, channel_mask, channels, bps-shift, sample_rate, options.foreign_metadata, /*flac_decoder_data=*/0))
+                               return EncoderSession_finish_error(&encoder_session);
+
+                       /*
+                        * first do any samples in the reservoir
+                        */
+                       if(options.common.sector_align && *options.common.align_reservoir_samples > 0) {
+                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) {
+                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       /*
+                        * decrement the data_bytes counter if we need to align the file
+                        */
+                       if(options.common.sector_align) {
+                               if(options.common.is_last_file) {
+                                       *options.common.align_reservoir_samples = 0;
+                               }
+                               else {
+                                       *options.common.align_reservoir_samples = align_remainder;
+                                       data_bytes -= (*options.common.align_reservoir_samples) * bytes_per_wide_sample;
+                               }
+                       }
+
+                       /*
+                        * now do from the file
+                        */
+                       while(data_bytes > 0) {
+                               bytes_read = fread(ucbuffer_, sizeof(unsigned char), min(data_bytes, CHUNK_OF_SAMPLES * bytes_per_wide_sample), infile);
+                               if(bytes_read == 0) {
+                                       if(ferror(infile)) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       else if(feof(infile)) {
+                                               if(options.common.ignore_chunk_sizes) {
+                                                       flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written);
+                                               }
+                                               else {
+                                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+                                                       if(encoder_session.treat_warnings_as_errors)
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               data_bytes = 0;
+                                       }
+                               }
+                               else {
+                                       if(bytes_read % bytes_per_wide_sample != 0) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       else {
+                                               unsigned wide_samples = bytes_read / bytes_per_wide_sample;
+                                               if(!format_input(input_, wide_samples, /*is_big_endian=*/false, is_unsigned_samples, channels, bps, shift, channel_map))
+                                                       return EncoderSession_finish_error(&encoder_session);
+
+                                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+                                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               data_bytes -= bytes_read;
+                                       }
+                               }
+                       }
+
+                       if(trim > 0) {
+                               FLAC__ASSERT(!options.common.sector_align);
+                               if(!fskip_ahead(infile, trim * bytes_per_wide_sample)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       /*
+                        * now read unaligned samples into reservoir or pad with zeroes if necessary
+                        */
+                       if(options.common.sector_align) {
+                               if(options.common.is_last_file) {
+                                       unsigned wide_samples = 588 - align_remainder;
+                                       if(wide_samples < 588) {
+                                               unsigned channel;
+
+                                               info_align_zero = wide_samples;
+                                               for(channel = 0; channel < channels; channel++)
+                                                       memset(input_[channel], 0, sizeof(input_[0][0]) * wide_samples);
+
+                                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+                                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                       }
+                               }
+                               else {
+                                       if(*options.common.align_reservoir_samples > 0) {
+                                               FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588);
+                                               bytes_read = fread(ucbuffer_, sizeof(unsigned char), (*options.common.align_reservoir_samples) * bytes_per_wide_sample, infile);
+                                               if(bytes_read == 0 && ferror(infile)) {
+                                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_wide_sample) {
+                                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)bytes_read, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+                                                       if(encoder_session.treat_warnings_as_errors)
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                               else {
+                                                       info_align_carry = *options.common.align_reservoir_samples;
+                                                       if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, /*is_big_endian=*/false, is_unsigned_samples, channels, bps, shift, channel_map))
+                                                               return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if(pad == true) {
+                               unsigned char tmp;
+
+                               if(fread(&tmp, 1U, 1U, infile) < 1U) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read of data pad byte\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+
+                       got_data_chunk = true;
+               }
+               else {
+                       if(xx == 0x61746164 && !got_fmt_chunk) { /* "data" */
+                               flac__utils_printf(stderr, 1, "%s: ERROR: got 'data' sub-chunk before 'fmt' sub-chunk\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       if(!options.foreign_metadata) {
+                               if(xx == 0x20746d66 && got_fmt_chunk) /* "fmt " */
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'fmt ' sub-chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename);
+                               else if(xx == 0x61746164) /* "data" */
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'data' sub-chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename);
+                               else
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown sub-chunk '%c%c%c%c' (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename, (char)(xx&255), (char)((xx>>8)&255), (char)((xx>>16)&255), (char)(xx>>24));
+                               if(encoder_session.treat_warnings_as_errors)
+                                       return EncoderSession_finish_error(&encoder_session);
+                       }
+
+                       /* sub-chunk size */
+                       if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
+                               return EncoderSession_finish_error(&encoder_session);
+                       else {
+                               unsigned long skip = xx+(xx & 1U);
+
+                               FLAC__ASSERT(skip<=LONG_MAX);
+                               if(!fskip_ahead(infile, skip)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over unsupported sub-chunk\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+               }
+       }
+
+       return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, options.foreign_metadata);
+}
+
+int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options)
+{
+       EncoderSession encoder_session;
+       size_t bytes_read;
+       const size_t bytes_per_wide_sample = options.channels * (options.bps >> 3);
+       unsigned align_remainder = 0;
+       int info_align_carry = -1, info_align_zero = -1;
+       FLAC__uint64 total_samples_in_input = 0;
+
+       FLAC__ASSERT(!options.common.sector_align || options.channels == 2);
+       FLAC__ASSERT(!options.common.sector_align || options.bps == 16);
+       FLAC__ASSERT(!options.common.sector_align || options.sample_rate == 44100);
+       FLAC__ASSERT(!options.common.sector_align || infilesize >= 0);
+       FLAC__ASSERT(!options.common.replay_gain || options.channels <= 2);
+       FLAC__ASSERT(!options.common.replay_gain || grabbag__replaygain_is_valid_sample_frequency(options.sample_rate));
+
+       if(!
+               EncoderSession_construct(
+                       &encoder_session,
+#if FLAC__HAS_OGG
+                       options.common.use_ogg,
+#else
+                       /*use_ogg=*/false,
+#endif
+                       options.common.verify,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       infile,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       /*
+        * now that we know the sample rate, canonicalize the
+        * --skip string to a number of samples:
+        */
+       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, options.sample_rate);
+       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+
+       if(infilesize < 0)
+               total_samples_in_input = 0;
+       else {
+               /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */
+               FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0);
+               total_samples_in_input = (FLAC__uint64)infilesize / bytes_per_wide_sample + *options.common.align_reservoir_samples;
+       }
+
+       /*
+        * now that we know the input size, canonicalize the
+        * --until strings to a number of samples:
+        */
+       if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, options.sample_rate, encoder_session.skip, total_samples_in_input))
+               return EncoderSession_finish_error(&encoder_session);
+       encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples;
+       FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0);
+
+       infilesize -= (off_t)encoder_session.skip * bytes_per_wide_sample;
+       encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip;
+       if(encoder_session.until > 0) {
+               const FLAC__uint64 trim = total_samples_in_input - encoder_session.until;
+               FLAC__ASSERT(total_samples_in_input > 0);
+               FLAC__ASSERT(!options.common.sector_align);
+               infilesize -= (off_t)trim * bytes_per_wide_sample;
+               encoder_session.total_samples_to_encode -= trim;
+       }
+       if(infilesize >= 0 && options.common.sector_align) {
+               FLAC__ASSERT(encoder_session.skip == 0);
+               align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
+               if(options.common.is_last_file)
+                       encoder_session.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */
+               else
+                       encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
+       }
+       encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample;
+
+       if(encoder_session.total_samples_to_encode <= 0)
+               flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+
+       if(encoder_session.skip > 0) {
+               unsigned skip_bytes = bytes_per_wide_sample * (unsigned)encoder_session.skip;
+               if(skip_bytes > lookahead_length) {
+                       skip_bytes -= lookahead_length;
+                       lookahead_length = 0;
+                       if(!fskip_ahead(infile, skip_bytes)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+               }
+               else {
+                       lookahead += skip_bytes;
+                       lookahead_length -= skip_bytes;
+               }
+       }
+
+       if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, options.channels, options.bps, options.sample_rate, /*foreign_metadata=*/0, /*flac_decoder_data=*/0))
+               return EncoderSession_finish_error(&encoder_session);
+
+       /*
+        * first do any samples in the reservoir
+        */
+       if(options.common.sector_align && *options.common.align_reservoir_samples > 0) {
+               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) {
+                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                       return EncoderSession_finish_error(&encoder_session);
+               }
+       }
+
+       /*
+        * decrement infilesize if we need to align the file
+        */
+       if(options.common.sector_align) {
+               FLAC__ASSERT(infilesize >= 0);
+               if(options.common.is_last_file) {
+                       *options.common.align_reservoir_samples = 0;
+               }
+               else {
+                       *options.common.align_reservoir_samples = align_remainder;
+                       infilesize -= (off_t)((*options.common.align_reservoir_samples) * bytes_per_wide_sample);
+                       FLAC__ASSERT(infilesize >= 0);
+               }
+       }
+
+       /*
+        * now do from the file
+        */
+       if(infilesize < 0) {
+               while(!feof(infile)) {
+                       if(lookahead_length > 0) {
+                               FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * bytes_per_wide_sample);
+                               memcpy(ucbuffer_, lookahead, lookahead_length);
+                               bytes_read = fread(ucbuffer_+lookahead_length, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample - lookahead_length, infile) + lookahead_length;
+                               if(ferror(infile)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               lookahead_length = 0;
+                       }
+                       else
+                               bytes_read = fread(ucbuffer_, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, infile);
+
+                       if(bytes_read == 0) {
+                               if(ferror(infile)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+                       else if(bytes_read % bytes_per_wide_sample != 0) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+                               return EncoderSession_finish_error(&encoder_session);
+                       }
+                       else {
+                               unsigned wide_samples = bytes_read / bytes_per_wide_sample;
+                               if(!format_input(input_, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0))
+                                       return EncoderSession_finish_error(&encoder_session);
+
+                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+               }
+       }
+       else {
+               const FLAC__uint64 max_input_bytes = infilesize;
+               FLAC__uint64 total_input_bytes_read = 0;
+               while(total_input_bytes_read < max_input_bytes) {
+                       {
+                               size_t wanted = (CHUNK_OF_SAMPLES * bytes_per_wide_sample);
+                               wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read);
+
+                               if(lookahead_length > 0) {
+                                       FLAC__ASSERT(lookahead_length <= wanted);
+                                       memcpy(ucbuffer_, lookahead, lookahead_length);
+                                       wanted -= lookahead_length;
+                                       bytes_read = lookahead_length;
+                                       if(wanted > 0) {
+                                               bytes_read += fread(ucbuffer_+lookahead_length, sizeof(unsigned char), wanted, infile);
+                                               if(ferror(infile)) {
+                                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                                       return EncoderSession_finish_error(&encoder_session);
+                                               }
+                                       }
+                                       lookahead_length = 0;
+                               }
+                               else
+                                       bytes_read = fread(ucbuffer_, sizeof(unsigned char), wanted, infile);
+                       }
+
+                       if(bytes_read == 0) {
+                               if(ferror(infile)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               else if(feof(infile)) {
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+                                       if(encoder_session.treat_warnings_as_errors)
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       total_input_bytes_read = max_input_bytes;
+                               }
+                       }
+                       else {
+                               if(bytes_read % bytes_per_wide_sample != 0) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               else {
+                                       unsigned wide_samples = bytes_read / bytes_per_wide_sample;
+                                       if(!format_input(input_, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0))
+                                               return EncoderSession_finish_error(&encoder_session);
+
+                                       if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+                                               print_error_with_state(&encoder_session, "ERROR during encoding");
+                                               return EncoderSession_finish_error(&encoder_session);
+                                       }
+                                       total_input_bytes_read += bytes_read;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * now read unaligned samples into reservoir or pad with zeroes if necessary
+        */
+       if(options.common.sector_align) {
+               if(options.common.is_last_file) {
+                       unsigned wide_samples = 588 - align_remainder;
+                       if(wide_samples < 588) {
+                               unsigned channel;
+
+                               info_align_zero = wide_samples;
+                               for(channel = 0; channel < options.channels; channel++)
+                                       memset(input_[channel], 0, sizeof(input_[0][0]) * wide_samples);
+
+                               if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) {
+                                       print_error_with_state(&encoder_session, "ERROR during encoding");
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+               }
+               else {
+                       if(*options.common.align_reservoir_samples > 0) {
+                               FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588);
+                               bytes_read = fread(ucbuffer_, sizeof(unsigned char), (*options.common.align_reservoir_samples) * bytes_per_wide_sample, infile);
+                               if(bytes_read == 0 && ferror(infile)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename);
+                                       return EncoderSession_finish_error(&encoder_session);
+                               }
+                               else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_wide_sample) {
+                                       flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)bytes_read, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+                                       if(encoder_session.treat_warnings_as_errors)
+                                               return EncoderSession_finish_error(&encoder_session);
+                               }
+                               else {
+                                       info_align_carry = *options.common.align_reservoir_samples;
+                                       if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0))
+                                               return EncoderSession_finish_error(&encoder_session);
+                               }
+                       }
+               }
+       }
+
+       return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, /*foreign_metadata=*/0);
+}
+
+int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options, FLAC__bool input_is_ogg)
+{
+       EncoderSession encoder_session;
+       FLAC__StreamDecoder *decoder = 0;
+       FLACDecoderData decoder_data;
+       size_t i;
+       int retval;
+
+       if(!
+               EncoderSession_construct(
+                       &encoder_session,
+#if FLAC__HAS_OGG
+                       options.common.use_ogg,
+#else
+                       /*use_ogg=*/false,
+#endif
+                       options.common.verify,
+                       options.common.treat_warnings_as_errors,
+                       options.common.continue_through_decode_errors,
+                       infile,
+                       infilename,
+                       outfilename
+               )
+       )
+               return 1;
+
+       decoder_data.encoder_session = &encoder_session;
+       decoder_data.filesize = (infilesize == (off_t)(-1)? 0 : infilesize);
+       decoder_data.lookahead = lookahead;
+       decoder_data.lookahead_length = lookahead_length;
+       decoder_data.num_metadata_blocks = 0;
+       decoder_data.samples_left_to_process = 0;
+       decoder_data.fatal_error = false;
+
+       /*
+        * set up FLAC decoder for the input
+        */
+       if (0 == (decoder = FLAC__stream_decoder_new())) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: creating decoder for FLAC input\n", encoder_session.inbasefilename);
+               return EncoderSession_finish_error(&encoder_session);
+       }
+       if (!(
+               FLAC__stream_decoder_set_md5_checking(decoder, false) &&
+               FLAC__stream_decoder_set_metadata_respond_all(decoder)
+       )) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", encoder_session.inbasefilename);
+               goto fubar1; /*@@@ yuck */
+       }
+
+       if (input_is_ogg) {
+               if (FLAC__stream_decoder_init_ogg_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+                       goto fubar1; /*@@@ yuck */
+               }
+       }
+       else if (FLAC__stream_decoder_init_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+               goto fubar1; /*@@@ yuck */
+       }
+
+       if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || decoder_data.fatal_error) {
+               if (decoder_data.fatal_error)
+                       flac__utils_printf(stderr, 1, "%s: ERROR: out of memory or too many metadata blocks while reading metadata in FLAC input\n", encoder_session.inbasefilename);
+               else
+                       flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+               goto fubar1; /*@@@ yuck */
+       }
+
+       if (decoder_data.num_metadata_blocks == 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", encoder_session.inbasefilename);
+               goto fubar2; /*@@@ yuck */
+       }
+       else if (decoder_data.metadata_blocks[0]->type != FLAC__METADATA_TYPE_STREAMINFO) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, first metadata block is not STREAMINFO\n", encoder_session.inbasefilename);
+               goto fubar2; /*@@@ yuck */
+       }
+       else if (decoder_data.metadata_blocks[0]->data.stream_info.total_samples == 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: FLAC input has STREAMINFO with unknown total samples which is not supported\n", encoder_session.inbasefilename);
+               goto fubar2; /*@@@ yuck */
+       }
+
+       /*
+        * now that we have the STREAMINFO and know the sample rate,
+        * canonicalize the --skip string to a number of samples:
+        */
+       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate);
+       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+       FLAC__ASSERT(!options.common.sector_align); /* --sector-align with FLAC input is not supported */
+
+       {
+               FLAC__uint64 total_samples_in_input, trim = 0;
+
+               total_samples_in_input = decoder_data.metadata_blocks[0]->data.stream_info.total_samples;
+
+               /*
+                * now that we know the input size, canonicalize the
+                * --until string to an absolute sample number:
+                */
+               if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, encoder_session.skip, total_samples_in_input))
+                       goto fubar2; /*@@@ yuck */
+               encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples;
+
+               encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip;
+               if(encoder_session.until > 0) {
+                       trim = total_samples_in_input - encoder_session.until;
+                       FLAC__ASSERT(total_samples_in_input > 0);
+                       encoder_session.total_samples_to_encode -= trim;
+               }
+
+               encoder_session.unencoded_size = decoder_data.filesize;
+
+               /* (channel mask will get copied over from the source VORBIS_COMMENT if it exists) */
+               if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, decoder_data.metadata_blocks[0]->data.stream_info.channels, decoder_data.metadata_blocks[0]->data.stream_info.bits_per_sample, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, /*foreign_metadata=*/0, &decoder_data))
+                       goto fubar2; /*@@@ yuck */
+
+               /*
+                * have to wait until the FLAC encoder is set up for writing
+                * before any seeking in the input FLAC file, because the seek
+                * itself will usually call the decoder's write callback, and
+                * our decoder's write callback passes samples to our FLAC
+                * encoder
+                */
+               decoder_data.samples_left_to_process = encoder_session.total_samples_to_encode;
+               if(encoder_session.skip > 0) {
+                       if(!FLAC__stream_decoder_seek_absolute(decoder, encoder_session.skip)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR while skipping samples, FLAC decoder state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+                               goto fubar2; /*@@@ yuck */
+                       }
+               }
+
+               /*
+                * now do samples from the file
+                */
+               while(!decoder_data.fatal_error && decoder_data.samples_left_to_process > 0) {
+                       /* We can also hit the end of stream without samples_left_to_process
+                        * going to 0 if there are errors and continue_through_decode_errors
+                        * is on, so we want to break in that case too:
+                        */
+                       if(encoder_session.continue_through_decode_errors && FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
+                               break;
+                       if(!FLAC__stream_decoder_process_single(decoder)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+                               goto fubar2; /*@@@ yuck */
+                       }
+               }
+               if(decoder_data.fatal_error) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+                       goto fubar2; /*@@@ yuck */
+               }
+       }
+
+       FLAC__stream_decoder_delete(decoder);
+       retval = EncoderSession_finish_ok(&encoder_session, -1, -1, /*foreign_metadata=*/0);
+       /* have to wail until encoder is completely finished before deleting because of the final step of writing the seekpoint offsets */
+       for(i = 0; i < decoder_data.num_metadata_blocks; i++)
+               FLAC__metadata_object_delete(decoder_data.metadata_blocks[i]);
+       return retval;
+
+fubar2:
+       for(i = 0; i < decoder_data.num_metadata_blocks; i++)
+               FLAC__metadata_object_delete(decoder_data.metadata_blocks[i]);
+fubar1:
+       FLAC__stream_decoder_delete(decoder);
+       return EncoderSession_finish_error(&encoder_session);
+}
+
+FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC__bool verify, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FILE *infile, const char *infilename, const char *outfilename)
+{
+       unsigned i;
+       FLAC__uint32 test = 1;
+
+       /*
+        * initialize globals
+        */
+
+       is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+               input_[i] = &(in_[i][0]);
+
+
+       /*
+        * initialize instance
+        */
+
+#if FLAC__HAS_OGG
+       e->use_ogg = use_ogg;
+#else
+       (void)use_ogg;
+#endif
+       e->verify = verify;
+       e->treat_warnings_as_errors = treat_warnings_as_errors;
+       e->continue_through_decode_errors = continue_through_decode_errors;
+
+       e->is_stdout = (0 == strcmp(outfilename, "-"));
+       e->outputfile_opened = false;
+
+       e->inbasefilename = grabbag__file_get_basename(infilename);
+       e->infilename = infilename;
+       e->outfilename = outfilename;
+
+       e->skip = 0; /* filled in later after the sample_rate is known */
+       e->unencoded_size = 0;
+       e->total_samples_to_encode = 0;
+       e->bytes_written = 0;
+       e->samples_written = 0;
+       e->stats_mask = 0;
+
+       e->encoder = 0;
+
+       e->fin = infile;
+       e->seek_table_template = 0;
+
+       if(0 == (e->seek_table_template = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE))) {
+               flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename);
+               return false;
+       }
+
+       e->encoder = FLAC__stream_encoder_new();
+       if(0 == e->encoder) {
+               flac__utils_printf(stderr, 1, "%s: ERROR creating the encoder instance\n", e->inbasefilename);
+               EncoderSession_destroy(e);
+               return false;
+       }
+
+       return true;
+}
+
+void EncoderSession_destroy(EncoderSession *e)
+{
+       if(e->fin != stdin)
+               fclose(e->fin);
+
+       if(0 != e->encoder) {
+               FLAC__stream_encoder_delete(e->encoder);
+               e->encoder = 0;
+       }
+
+       if(0 != e->seek_table_template) {
+               FLAC__metadata_object_delete(e->seek_table_template);
+               e->seek_table_template = 0;
+       }
+}
+
+int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata)
+{
+       FLAC__StreamEncoderState fse_state = FLAC__STREAM_ENCODER_OK;
+       int ret = 0;
+       FLAC__bool verify_error = false;
+
+       if(e->encoder) {
+               fse_state = FLAC__stream_encoder_get_state(e->encoder);
+               ret = FLAC__stream_encoder_finish(e->encoder)? 0 : 1;
+               verify_error =
+                       fse_state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA ||
+                       FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA
+               ;
+       }
+       /* all errors except verify errors should interrupt the stats */
+       if(ret && !verify_error)
+               print_error_with_state(e, "ERROR during encoding");
+       else if(e->total_samples_to_encode > 0) {
+               print_stats(e);
+               flac__utils_printf(stderr, 2, "\n");
+       }
+
+       if(verify_error) {
+               print_verify_error(e);
+               ret = 1;
+       }
+       else {
+               if(info_align_carry >= 0) {
+                       flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d samples to be carried over\n", e->inbasefilename, info_align_carry);
+               }
+               if(info_align_zero >= 0) {
+                       flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d zero samples to be appended\n", e->inbasefilename, info_align_zero);
+               }
+       }
+
+       /*@@@@@@ should this go here or somewhere else? */
+       if(ret == 0 && foreign_metadata) {
+               const char *error;
+               if(!flac__foreign_metadata_write_to_flac(foreign_metadata, e->infilename, e->outfilename, &error)) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: updating foreign metadata in FLAC file: %s\n", e->inbasefilename, error);
+                       ret = 1;
+               }
+       }
+
+       EncoderSession_destroy(e);
+
+       return ret;
+}
+
+int EncoderSession_finish_error(EncoderSession *e)
+{
+       FLAC__ASSERT(e->encoder);
+
+       if(e->total_samples_to_encode > 0)
+               flac__utils_printf(stderr, 2, "\n");
+
+       if(FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
+               print_verify_error(e);
+       else if(e->outputfile_opened)
+               /* only want to delete the file if we opened it; otherwise it could be an existing file and our overwrite failed */
+               unlink(e->outfilename);
+
+       EncoderSession_destroy(e);
+
+       return 1;
+}
+
+typedef struct {
+       unsigned num_metadata;
+       FLAC__bool *needs_delete;
+       FLAC__StreamMetadata **metadata;
+       FLAC__StreamMetadata *cuesheet; /* always needs to be deleted */
+} static_metadata_t;
+
+static void static_metadata_init(static_metadata_t *m)
+{
+       m->num_metadata = 0;
+       m->needs_delete = 0;
+       m->metadata = 0;
+       m->cuesheet = 0;
+}
+
+static void static_metadata_clear(static_metadata_t *m)
+{
+       unsigned i;
+       for(i = 0; i < m->num_metadata; i++)
+               if(m->needs_delete[i])
+                       FLAC__metadata_object_delete(m->metadata[i]);
+       if(m->metadata)
+               free(m->metadata);
+       if(m->needs_delete)
+               free(m->needs_delete);
+       if(m->cuesheet)
+               FLAC__metadata_object_delete(m->cuesheet);
+       static_metadata_init(m);
+}
+
+static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetadata *d, FLAC__bool needs_delete)
+{
+       void *x;
+       if(0 == (x = safe_realloc_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/)))
+               return false;
+       m->metadata = (FLAC__StreamMetadata**)x;
+       if(0 == (x = safe_realloc_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/)))
+               return false;
+       m->needs_delete = (FLAC__bool*)x;
+       m->metadata[m->num_metadata] = d;
+       m->needs_delete[m->num_metadata] = needs_delete;
+       m->num_metadata++;
+       return true;
+}
+
+FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, FLAC__uint32 channel_mask, unsigned channels, unsigned bps, unsigned sample_rate, const foreign_metadata_t *foreign_metadata, FLACDecoderData *flac_decoder_data)
+{
+       FLAC__StreamMetadata padding;
+       FLAC__StreamMetadata **metadata = 0;
+       static_metadata_t static_metadata;
+       unsigned num_metadata = 0, i;
+       FLAC__StreamEncoderInitStatus init_status;
+       const FLAC__bool is_cdda = (channels == 1 || channels == 2) && (bps == 16) && (sample_rate == 44100);
+       char apodizations[2000];
+
+       FLAC__ASSERT(sizeof(options.pictures)/sizeof(options.pictures[0]) <= 64);
+
+       static_metadata_init(&static_metadata);
+
+       e->replay_gain = options.replay_gain;
+       e->channels = channels;
+       e->bits_per_sample = bps;
+       e->sample_rate = sample_rate;
+
+       apodizations[0] = '\0';
+
+       if(e->replay_gain) {
+               if(channels != 1 && channels != 2) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR, number of channels (%u) must be 1 or 2 for --replay-gain\n", e->inbasefilename, channels);
+                       return false;
+               }
+               if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR, invalid sample rate (%u) for --replay-gain\n", e->inbasefilename, sample_rate);
+                       return false;
+               }
+               if(options.is_first_file) {
+                       if(!grabbag__replaygain_init(sample_rate)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR initializing ReplayGain stage\n", e->inbasefilename);
+                               return false;
+                       }
+               }
+       }
+
+       if(!parse_cuesheet(&static_metadata.cuesheet, options.cuesheet_filename, e->inbasefilename, is_cdda, e->total_samples_to_encode, e->treat_warnings_as_errors))
+               return false;
+
+       if(!convert_to_seek_table_template(options.requested_seek_points, options.num_requested_seek_points, options.cued_seekpoints? static_metadata.cuesheet : 0, e)) {
+               flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename);
+               static_metadata_clear(&static_metadata);
+               return false;
+       }
+
+       /* build metadata */
+       if(flac_decoder_data) {
+               /*
+                * we're encoding from FLAC so we will use the FLAC file's
+                * metadata as the basis for the encoded file
+                */
+               {
+                       /*
+                        * first handle pictures: simple append any --pictures
+                        * specified.
+                        */
+                       for(i = 0; i < options.num_pictures; i++) {
+                               FLAC__StreamMetadata *pic = FLAC__metadata_object_clone(options.pictures[i]);
+                               if(0 == pic) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PICTURE block\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks++] = pic;
+                       }
+               }
+               {
+                       /*
+                        * next handle vorbis comment: if any tags were specified
+                        * or there is no existing vorbis comment, we create a
+                        * new vorbis comment (discarding any existing one); else
+                        * we keep the existing one.  also need to make sure to
+                        * propagate any channel mask tag.
+                        */
+                       /* @@@ change to append -T values from options.vorbis_comment if input has VC already? */
+                       size_t i, j;
+                       FLAC__bool vc_found = false;
+                       for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+                                       vc_found = true;
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && options.vorbis_comment->data.vorbis_comment.num_comments > 0) {
+                                       (void) flac__utils_get_channel_mask_tag(flac_decoder_data->metadata_blocks[i], &channel_mask);
+                                       flac__utils_printf(stderr, 1, "%s: WARNING, replacing tags from input FLAC file with those given on the command-line\n", e->inbasefilename);
+                                       if(e->treat_warnings_as_errors) {
+                                               static_metadata_clear(&static_metadata);
+                                               return false;
+                                       }
+                                       FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+                                       flac_decoder_data->metadata_blocks[i] = 0;
+                               }
+                               else
+                                       flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+                       }
+                       flac_decoder_data->num_metadata_blocks = j;
+                       if((!vc_found || options.vorbis_comment->data.vorbis_comment.num_comments > 0) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+                               /* prepend ours */
+                               FLAC__StreamMetadata *vc = FLAC__metadata_object_clone(options.vorbis_comment);
+                               if(0 == vc || (channel_mask && !flac__utils_set_channel_mask_tag(vc, channel_mask))) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for VORBIS_COMMENT block\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+                                       flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+                               flac_decoder_data->metadata_blocks[1] = vc;
+                               flac_decoder_data->num_metadata_blocks++;
+                       }
+               }
+               {
+                       /*
+                        * next handle cuesheet: if --cuesheet was specified, use
+                        * it; else if file has existing CUESHEET and cuesheet's
+                        * lead-out offset is correct, keep it; else no CUESHEET
+                        */
+                       size_t i, j;
+                       for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+                               FLAC__bool existing_cuesheet_is_bad = false;
+                               /* check if existing cuesheet matches the input audio */
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && 0 == static_metadata.cuesheet) {
+                                       const FLAC__StreamMetadata_CueSheet *cs = &flac_decoder_data->metadata_blocks[i]->data.cue_sheet;
+                                       if(e->total_samples_to_encode == 0) {
+                                               flac__utils_printf(stderr, 1, "%s: WARNING, cuesheet in input FLAC file cannot be kept if input size is not known, dropping it...\n", e->inbasefilename);
+                                               if(e->treat_warnings_as_errors) {
+                                                       static_metadata_clear(&static_metadata);
+                                                       return false;
+                                               }
+                                               existing_cuesheet_is_bad = true;
+                                       }
+                                       else if(e->total_samples_to_encode != cs->tracks[cs->num_tracks-1].offset) {
+                                               flac__utils_printf(stderr, 1, "%s: WARNING, lead-out offset of cuesheet in input FLAC file does not match input length, dropping existing cuesheet...\n", e->inbasefilename);
+                                               if(e->treat_warnings_as_errors) {
+                                                       static_metadata_clear(&static_metadata);
+                                                       return false;
+                                               }
+                                               existing_cuesheet_is_bad = true;
+                                       }
+                               }
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && (existing_cuesheet_is_bad || 0 != static_metadata.cuesheet)) {
+                                       if(0 != static_metadata.cuesheet) {
+                                               flac__utils_printf(stderr, 1, "%s: WARNING, replacing cuesheet in input FLAC file with the one given on the command-line\n", e->inbasefilename);
+                                               if(e->treat_warnings_as_errors) {
+                                                       static_metadata_clear(&static_metadata);
+                                                       return false;
+                                               }
+                                       }
+                                       FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+                                       flac_decoder_data->metadata_blocks[i] = 0;
+                               }
+                               else
+                                       flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+                       }
+                       flac_decoder_data->num_metadata_blocks = j;
+                       if(0 != static_metadata.cuesheet && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+                               /* prepend ours */
+                               FLAC__StreamMetadata *cs = FLAC__metadata_object_clone(static_metadata.cuesheet);
+                               if(0 == cs) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for CUESHEET block\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+                                       flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+                               flac_decoder_data->metadata_blocks[1] = cs;
+                               flac_decoder_data->num_metadata_blocks++;
+                       }
+               }
+               {
+                       /*
+                        * next handle seektable: if -S- was specified, no
+                        * SEEKTABLE; else if -S was specified, use it/them;
+                        * else if file has existing SEEKTABLE and input size is
+                        * preserved (no --skip/--until/etc specified), keep it;
+                        * else use default seektable options
+                        *
+                        * note: meanings of num_requested_seek_points:
+                        *  -1 : no -S option given, default to some value
+                        *   0 : -S- given (no seektable)
+                        *  >0 : one or more -S options given
+                        */
+                       size_t i, j;
+                       FLAC__bool existing_seektable = false;
+                       for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE)
+                                       existing_seektable = true;
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE && (e->total_samples_to_encode != flac_decoder_data->metadata_blocks[0]->data.stream_info.total_samples || options.num_requested_seek_points >= 0)) {
+                                       if(options.num_requested_seek_points > 0) {
+                                               flac__utils_printf(stderr, 1, "%s: WARNING, replacing seektable in input FLAC file with the one given on the command-line\n", e->inbasefilename);
+                                               if(e->treat_warnings_as_errors) {
+                                                       static_metadata_clear(&static_metadata);
+                                                       return false;
+                                               }
+                                       }
+                                       else if(options.num_requested_seek_points == 0)
+                                               ; /* no warning, silently delete existing SEEKTABLE since user specified --no-seektable (-S-) */
+                                       else {
+                                               flac__utils_printf(stderr, 1, "%s: WARNING, can't use existing seektable in input FLAC since the input size is changing or unknown, dropping existing SEEKTABLE block...\n", e->inbasefilename);
+                                               if(e->treat_warnings_as_errors) {
+                                                       static_metadata_clear(&static_metadata);
+                                                       return false;
+                                               }
+                                       }
+                                       FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+                                       flac_decoder_data->metadata_blocks[i] = 0;
+                                       existing_seektable = false;
+                               }
+                               else
+                                       flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+                       }
+                       flac_decoder_data->num_metadata_blocks = j;
+                       if((options.num_requested_seek_points > 0 || (options.num_requested_seek_points < 0 && !existing_seektable)) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+                               /* prepend ours */
+                               FLAC__StreamMetadata *st = FLAC__metadata_object_clone(e->seek_table_template);
+                               if(0 == st) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for SEEKTABLE block\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--)
+                                       flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1];
+                               flac_decoder_data->metadata_blocks[1] = st;
+                               flac_decoder_data->num_metadata_blocks++;
+                       }
+               }
+               {
+                       /*
+                        * finally handle padding: if --no-padding was specified,
+                        * then delete all padding; else if -P was specified,
+                        * use that instead of existing padding (if any); else
+                        * if existing file has padding, move all existing
+                        * padding blocks to one padding block at the end; else
+                        * use default padding.
+                        */
+                       int p = -1;
+                       size_t i, j;
+                       for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) {
+                               if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_PADDING) {
+                                       if(p < 0)
+                                               p = 0;
+                                       p += flac_decoder_data->metadata_blocks[i]->length;
+                                       FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]);
+                                       flac_decoder_data->metadata_blocks[i] = 0;
+                               }
+                               else
+                                       flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i];
+                       }
+                       flac_decoder_data->num_metadata_blocks = j;
+                       if(options.padding > 0)
+                               p = options.padding;
+                       if(p < 0)
+                               p = e->total_samples_to_encode / e->sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8;
+                       if(options.padding != 0) {
+                               if(p > 0 && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) {
+                                       flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+                                       if(0 == flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PADDING block\n", e->inbasefilename);
+                                               static_metadata_clear(&static_metadata);
+                                               return false;
+                                       }
+                                       flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->is_last = false; /* the encoder will set this for us */
+                                       flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->length = p;
+                                       flac_decoder_data->num_metadata_blocks++;
+                               }
+                       }
+               }
+               metadata = &flac_decoder_data->metadata_blocks[1]; /* don't include STREAMINFO */
+               num_metadata = flac_decoder_data->num_metadata_blocks - 1;
+       }
+       else {
+               /*
+                * we're not encoding from FLAC so we will build the metadata
+                * from scratch
+                */
+               if(e->seek_table_template->data.seek_table.num_points > 0) {
+                       e->seek_table_template->is_last = false; /* the encoder will set this for us */
+                       static_metadata_append(&static_metadata, e->seek_table_template, /*needs_delete=*/false);
+               }
+               if(0 != static_metadata.cuesheet)
+                       static_metadata_append(&static_metadata, static_metadata.cuesheet, /*needs_delete=*/false);
+               if(channel_mask) {
+                       if(!flac__utils_set_channel_mask_tag(options.vorbis_comment, channel_mask)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR adding channel mask tag\n", e->inbasefilename);
+                               static_metadata_clear(&static_metadata);
+                               return false;
+                       }
+               }
+               static_metadata_append(&static_metadata, options.vorbis_comment, /*needs_delete=*/false);
+               for(i = 0; i < options.num_pictures; i++)
+                       static_metadata_append(&static_metadata, options.pictures[i], /*needs_delete=*/false);
+               if(foreign_metadata) {
+                       for(i = 0; i < foreign_metadata->num_blocks; i++) {
+                               FLAC__StreamMetadata *p = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+                               if(!p) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: out of memory\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               static_metadata_append(&static_metadata, p, /*needs_delete=*/true);
+                               static_metadata.metadata[static_metadata.num_metadata-1]->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8 + foreign_metadata->blocks[i].size;
+/*fprintf(stderr,"@@@@@@ add PADDING=%u\n",static_metadata.metadata[static_metadata.num_metadata-1]->length);*/
+                       }
+               }
+               if(options.padding != 0) {
+                       padding.is_last = false; /* the encoder will set this for us */
+                       padding.type = FLAC__METADATA_TYPE_PADDING;
+                       padding.length = (unsigned)(options.padding>0? options.padding : (e->total_samples_to_encode / e->sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8));
+                       static_metadata_append(&static_metadata, &padding, /*needs_delete=*/false);
+               }
+               metadata = static_metadata.metadata;
+               num_metadata = static_metadata.num_metadata;
+       }
+
+       /* check for a few things that have not already been checked.  the
+        * FLAC__stream_encoder_init*() will check it but only return
+        * FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA so we check some
+        * up front to give a better error message.
+        */
+       if(!verify_metadata(e, metadata, num_metadata)) {
+               static_metadata_clear(&static_metadata);
+               return false;
+       }
+
+       FLAC__stream_encoder_set_verify(e->encoder, options.verify);
+       FLAC__stream_encoder_set_streamable_subset(e->encoder, !options.lax);
+       FLAC__stream_encoder_set_channels(e->encoder, channels);
+       FLAC__stream_encoder_set_bits_per_sample(e->encoder, bps);
+       FLAC__stream_encoder_set_sample_rate(e->encoder, sample_rate);
+       for(i = 0; i < options.num_compression_settings; i++) {
+               switch(options.compression_settings[i].type) {
+                       case CST_BLOCKSIZE:
+                               FLAC__stream_encoder_set_blocksize(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_COMPRESSION_LEVEL:
+                               FLAC__stream_encoder_set_compression_level(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               apodizations[0] = '\0';
+                               break;
+                       case CST_DO_MID_SIDE:
+                               FLAC__stream_encoder_set_do_mid_side_stereo(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_LOOSE_MID_SIDE:
+                               FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_APODIZATION:
+                               if(strlen(apodizations)+strlen(options.compression_settings[i].value.t_string)+2 >= sizeof(apodizations)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: too many apodization functions requested\n", e->inbasefilename);
+                                       static_metadata_clear(&static_metadata);
+                                       return false;
+                               }
+                               else {
+                                       strcat(apodizations, options.compression_settings[i].value.t_string);
+                                       strcat(apodizations, ";");
+                               }
+                               break;
+                       case CST_MAX_LPC_ORDER:
+                               FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_QLP_COEFF_PRECISION:
+                               FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_DO_QLP_COEFF_PREC_SEARCH:
+                               FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_DO_ESCAPE_CODING:
+                               FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_DO_EXHAUSTIVE_MODEL_SEARCH:
+                               FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_MIN_RESIDUAL_PARTITION_ORDER:
+                               FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_MAX_RESIDUAL_PARTITION_ORDER:
+                               FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_RICE_PARAMETER_SEARCH_DIST:
+                               FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+               }
+       }
+       if(*apodizations)
+               FLAC__stream_encoder_set_apodization(e->encoder, apodizations);
+       FLAC__stream_encoder_set_total_samples_estimate(e->encoder, e->total_samples_to_encode);
+       FLAC__stream_encoder_set_metadata(e->encoder, (num_metadata > 0)? metadata : 0, num_metadata);
+
+       FLAC__stream_encoder_disable_constant_subframes(e->encoder, options.debug.disable_constant_subframes);
+       FLAC__stream_encoder_disable_fixed_subframes(e->encoder, options.debug.disable_fixed_subframes);
+       FLAC__stream_encoder_disable_verbatim_subframes(e->encoder, options.debug.disable_verbatim_subframes);
+       if(!options.debug.do_md5) {
+               flac__utils_printf(stderr, 1, "%s: WARNING, MD5 computation disabled, resulting file will not have MD5 sum\n", e->inbasefilename);
+               if(e->treat_warnings_as_errors) {
+                       static_metadata_clear(&static_metadata);
+                       return false;
+               }
+               FLAC__stream_encoder_set_do_md5(e->encoder, false);
+       }
+
+#if FLAC__HAS_OGG
+       if(e->use_ogg) {
+               FLAC__stream_encoder_set_ogg_serial_number(e->encoder, options.serial_number);
+
+               init_status = FLAC__stream_encoder_init_ogg_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e);
+       }
+       else
+#endif
+       {
+               init_status = FLAC__stream_encoder_init_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e);
+       }
+
+       if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+               print_error_with_init_status(e, "ERROR initializing encoder", init_status);
+               if(FLAC__stream_encoder_get_state(e->encoder) != FLAC__STREAM_ENCODER_IO_ERROR)
+                       e->outputfile_opened = true;
+               static_metadata_clear(&static_metadata);
+               return false;
+       }
+       else
+               e->outputfile_opened = true;
+
+       e->stats_mask =
+               (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) && FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x07 :
+               (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x0f :
+               0x3f;
+
+       static_metadata_clear(&static_metadata);
+
+       return true;
+}
+
+FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], unsigned samples)
+{
+       if(e->replay_gain) {
+               if(!grabbag__replaygain_analyze(buffer, e->channels==2, e->bits_per_sample, samples)) {
+                       flac__utils_printf(stderr, 1, "%s: WARNING, error while calculating ReplayGain\n", e->inbasefilename);
+                       if(e->treat_warnings_as_errors)
+                               return false;
+               }
+       }
+
+       return FLAC__stream_encoder_process(e->encoder, buffer, samples);
+}
+
+FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e)
+{
+       const FLAC__bool only_placeholders = e->is_stdout;
+       FLAC__bool has_real_points;
+
+       if(num_requested_seek_points == 0 && 0 == cuesheet)
+               return true;
+
+       if(num_requested_seek_points < 0) {
+#if FLAC__HAS_OGG
+               /*@@@@@@ workaround ogg bug: too many seekpoints makes table not fit in one page */
+               if(e->use_ogg && e->total_samples_to_encode > 0 && e->total_samples_to_encode / e->sample_rate / 10 > 230)
+                       requested_seek_points = "230x;";
+               else 
+#endif
+                       requested_seek_points = "10s;";
+               num_requested_seek_points = 1;
+       }
+
+       if(num_requested_seek_points > 0) {
+               if(!grabbag__seektable_convert_specification_to_template(requested_seek_points, only_placeholders, e->total_samples_to_encode, e->sample_rate, e->seek_table_template, &has_real_points))
+                       return false;
+       }
+
+       if(0 != cuesheet) {
+               unsigned i, j;
+               const FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
+               for(i = 0; i < cs->num_tracks; i++) {
+                       const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+i;
+                       for(j = 0; j < tr->num_indices; j++) {
+                               if(!FLAC__metadata_object_seektable_template_append_point(e->seek_table_template, tr->offset + tr->indices[j].offset))
+                                       return false;
+                               has_real_points = true;
+                       }
+               }
+               if(has_real_points)
+                       if(!FLAC__metadata_object_seektable_template_sort(e->seek_table_template, /*compact=*/true))
+                               return false;
+       }
+
+       if(has_real_points) {
+               if(e->is_stdout) {
+                       flac__utils_printf(stderr, 1, "%s: WARNING, cannot write back seekpoints when encoding to stdout\n", e->inbasefilename);
+                       if(e->treat_warnings_as_errors)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+       /* convert from mm:ss.sss to sample number if necessary */
+       flac__utils_canonicalize_skip_until_specification(spec, sample_rate);
+
+       /* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */
+       if(spec->is_relative && spec->value.samples == 0) {
+               spec->is_relative = false;
+               return true;
+       }
+
+       /* in any other case the total samples in the input must be known */
+       if(total_samples_in_input == 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when input length is unknown\n", inbasefilename);
+               return false;
+       }
+
+       FLAC__ASSERT(spec->value_is_samples);
+
+       /* convert relative specifications to absolute */
+       if(spec->is_relative) {
+               if(spec->value.samples <= 0)
+                       spec->value.samples += (FLAC__int64)total_samples_in_input;
+               else
+                       spec->value.samples += skip;
+               spec->is_relative = false;
+       }
+
+       /* error check */
+       if(spec->value.samples < 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename);
+               return false;
+       }
+       if((FLAC__uint64)spec->value.samples <= skip) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename);
+               return false;
+       }
+       if((FLAC__uint64)spec->value.samples > total_samples_in_input) {
+               flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename);
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, unsigned num_metadata)
+{
+       FLAC__bool metadata_picture_has_type1 = false;
+       FLAC__bool metadata_picture_has_type2 = false;
+       unsigned i;
+
+       FLAC__ASSERT(0 != metadata);
+       for(i = 0; i < num_metadata; i++) {
+               const FLAC__StreamMetadata *m = metadata[i];
+               if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+                       if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: SEEKTABLE metadata block is invalid\n", e->inbasefilename);
+                               return false;
+                       }
+               }
+               else if(m->type == FLAC__METADATA_TYPE_CUESHEET) {
+                       if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: CUESHEET metadata block is invalid\n", e->inbasefilename);
+                               return false;
+                       }
+               }
+               else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
+                       const char *error = 0;
+                       if(!FLAC__format_picture_is_legal(&m->data.picture, &error)) {
+                               flac__utils_printf(stderr, 1, "%s: ERROR: PICTURE metadata block is invalid: %s\n", e->inbasefilename, error);
+                               return false;
+                       }
+                       if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+                               if(metadata_picture_has_type1) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 1 (32x32 icon) in the file\n", e->inbasefilename);
+                                       return false;
+                               }
+                               metadata_picture_has_type1 = true;
+                       }
+                       else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+                               if(metadata_picture_has_type2) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 2 (icon) in the file\n", e->inbasefilename);
+                                       return false;
+                               }
+                               metadata_picture_has_type2 = true;
+                       }
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned shift, size_t *channel_map)
+{
+       unsigned wide_sample, sample, channel, byte;
+       FLAC__int32 *out[FLAC__MAX_CHANNELS];
+
+       if(0 == channel_map) {
+               for(channel = 0; channel < channels; channel++)
+                       out[channel] = dest[channel];
+       }
+       else {
+               for(channel = 0; channel < channels; channel++)
+                       out[channel] = dest[channel_map[channel]];
+       }
+
+       if(bps == 8) {
+               if(is_unsigned_samples) {
+                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++)
+                                       out[channel][wide_sample] = (FLAC__int32)ucbuffer_[sample] - 0x80;
+               }
+               else {
+                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++)
+                                       out[channel][wide_sample] = (FLAC__int32)scbuffer_[sample];
+               }
+       }
+       else if(bps == 16) {
+               if(is_big_endian != is_big_endian_host_) {
+                       unsigned char tmp;
+                       const unsigned bytes = wide_samples * channels * (bps >> 3);
+                       for(byte = 0; byte < bytes; byte += 2) {
+                               tmp = ucbuffer_[byte];
+                               ucbuffer_[byte] = ucbuffer_[byte+1];
+                               ucbuffer_[byte+1] = tmp;
+                       }
+               }
+               if(is_unsigned_samples) {
+                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++)
+                                       out[channel][wide_sample] = (FLAC__int32)usbuffer_[sample] - 0x8000;
+               }
+               else {
+                       for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++)
+                                       out[channel][wide_sample] = (FLAC__int32)ssbuffer_[sample];
+               }
+       }
+       else if(bps == 24) {
+               if(!is_big_endian) {
+                       unsigned char tmp;
+                       const unsigned bytes = wide_samples * channels * (bps >> 3);
+                       for(byte = 0; byte < bytes; byte += 3) {
+                               tmp = ucbuffer_[byte];
+                               ucbuffer_[byte] = ucbuffer_[byte+2];
+                               ucbuffer_[byte+2] = tmp;
+                       }
+               }
+               if(is_unsigned_samples) {
+                       for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++) {
+                                       out[channel][wide_sample]  = ucbuffer_[byte++]; out[channel][wide_sample] <<= 8;
+                                       out[channel][wide_sample] |= ucbuffer_[byte++]; out[channel][wide_sample] <<= 8;
+                                       out[channel][wide_sample] |= ucbuffer_[byte++];
+                                       out[channel][wide_sample] -= 0x800000;
+                               }
+               }
+               else {
+                       for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                               for(channel = 0; channel < channels; channel++, sample++) {
+                                       out[channel][wide_sample]  = scbuffer_[byte++]; out[channel][wide_sample] <<= 8;
+                                       out[channel][wide_sample] |= ucbuffer_[byte++]; out[channel][wide_sample] <<= 8;
+                                       out[channel][wide_sample] |= ucbuffer_[byte++];
+                               }
+               }
+       }
+       else {
+               FLAC__ASSERT(0);
+       }
+       if(shift > 0) {
+               FLAC__int32 mask = (1<<shift)-1;
+               for(wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+                       for(channel = 0; channel < channels; channel++) {
+                               if(out[channel][wide_sample] & mask) {
+                                       flac__utils_printf(stderr, 1, "ERROR during read, sample data (channel#%u sample#%u = %d) has non-zero least-significant bits\n  WAVE/AIFF header said the last %u bits are not significant and should be zero.\n", channel, wide_sample, out[channel][wide_sample], shift);
+                                       return false;
+                               }
+                               out[channel][wide_sample] >>= shift;
+                       }
+       }
+       return true;
+}
+
+void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+       EncoderSession *encoder_session = (EncoderSession*)client_data;
+
+       (void)encoder, (void)total_frames_estimate;
+
+       encoder_session->bytes_written = bytes_written;
+       encoder_session->samples_written = samples_written;
+
+       if(encoder_session->total_samples_to_encode > 0 && !((frames_written-1) & encoder_session->stats_mask))
+               print_stats(encoder_session);
+}
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       size_t n = 0;
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       if (data->fatal_error)
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+       /* use up lookahead first */
+       if (data->lookahead_length) {
+               n = min(data->lookahead_length, *bytes);
+               memcpy(buffer, data->lookahead, n);
+               buffer += n;
+               data->lookahead += n;
+               data->lookahead_length -= n;
+       }
+
+       /* get the rest from file */
+       if (*bytes > n) {
+               *bytes = n + fread(buffer, 1, *bytes-n, data->encoder_session->fin);
+               if(ferror(data->encoder_session->fin))
+                       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+               else if(0 == *bytes)
+                       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+               else
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+       }
+       else
+               return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       if(fseeko(data->encoder_session->fin, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       off_t pos;
+       (void)decoder;
+
+       if((pos = ftello(data->encoder_session->fin)) < 0)
+               return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+       else {
+               *absolute_byte_offset = (FLAC__uint64)pos;
+               return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+       }
+}
+
+FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       if(0 == data->filesize)
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+       else {
+               *stream_length = (FLAC__uint64)data->filesize;
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+       }
+}
+
+FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       return feof(data->encoder_session->fin)? true : false;
+}
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       FLAC__uint64 n = min(data->samples_left_to_process, frame->header.blocksize);
+       (void)decoder;
+
+       if(!EncoderSession_process(data->encoder_session, buffer, (unsigned)n)) {
+               print_error_with_state(data->encoder_session, "ERROR during encoding");
+               data->fatal_error = true;
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+
+       data->samples_left_to_process -= n;
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       if (data->fatal_error)
+               return;
+
+       if (
+               data->num_metadata_blocks == sizeof(data->metadata_blocks)/sizeof(data->metadata_blocks[0]) ||
+               0 == (data->metadata_blocks[data->num_metadata_blocks] = FLAC__metadata_object_clone(metadata))
+       )
+               data->fatal_error = true;
+       else
+               data->num_metadata_blocks++;
+}
+
+void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       FLACDecoderData *data = (FLACDecoderData*)client_data;
+       (void)decoder;
+
+       flac__utils_printf(stderr, 1, "%s: ERROR got %s while decoding FLAC input\n", data->encoder_session->inbasefilename, FLAC__StreamDecoderErrorStatusString[status]);
+       if(!data->encoder_session->continue_through_decode_errors)
+               data->fatal_error = true;
+}
+
+FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors)
+{
+       FILE *f;
+       unsigned last_line_read;
+       const char *error_message;
+
+       if(0 == cuesheet_filename)
+               return true;
+
+       if(lead_out_offset == 0) {
+               flac__utils_printf(stderr, 1, "%s: ERROR cannot import cuesheet when the number of input samples to encode is unknown\n", inbasefilename);
+               return false;
+       }
+
+       if(0 == (f = fopen(cuesheet_filename, "r"))) {
+               flac__utils_printf(stderr, 1, "%s: ERROR opening cuesheet \"%s\" for reading: %s\n", inbasefilename, cuesheet_filename, strerror(errno));
+               return false;
+       }
+
+       *cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, is_cdda, lead_out_offset);
+
+       fclose(f);
+
+       if(0 == *cuesheet) {
+               flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\" on line %u: %s\n", inbasefilename, cuesheet_filename, last_line_read, error_message);
+               return false;
+       }
+
+       if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) {
+               flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\": %s\n", inbasefilename, cuesheet_filename, error_message);
+               return false;
+       }
+
+       /* if we're expecting CDDA, warn about non-compliance */
+       if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) {
+               flac__utils_printf(stderr, 1, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", inbasefilename, cuesheet_filename, error_message);
+               if(treat_warnings_as_errors)
+                       return false;
+               (*cuesheet)->data.cue_sheet.is_cd = false;
+       }
+
+       return true;
+}
+
+void print_stats(const EncoderSession *encoder_session)
+{
+       const FLAC__uint64 samples_written = min(encoder_session->total_samples_to_encode, encoder_session->samples_written);
+#if defined _MSC_VER || defined __MINGW32__
+       /* with MSVC you have to spoon feed it the casting */
+       const double progress = (double)(FLAC__int64)samples_written / (double)(FLAC__int64)encoder_session->total_samples_to_encode;
+       const double ratio = (double)(FLAC__int64)encoder_session->bytes_written / ((double)(FLAC__int64)encoder_session->unencoded_size * min(1.0, progress));
+#else
+       const double progress = (double)samples_written / (double)encoder_session->total_samples_to_encode;
+       const double ratio = (double)encoder_session->bytes_written / ((double)encoder_session->unencoded_size * min(1.0, progress));
+#endif
+
+       FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
+
+       if(samples_written == encoder_session->total_samples_to_encode) {
+               flac__utils_printf(stderr, 2, "\r%s:%s wrote %u bytes, ratio=%0.3f",
+                       encoder_session->inbasefilename,
+                       encoder_session->verify? " Verify OK," : "",
+                       (unsigned)encoder_session->bytes_written,
+                       ratio
+               );
+       }
+       else {
+               flac__utils_printf(stderr, 2, "\r%s: %u%% complete, ratio=%0.3f", encoder_session->inbasefilename, (unsigned)floor(progress * 100.0 + 0.5), ratio);
+       }
+}
+
+void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status)
+{
+       const int ilen = strlen(e->inbasefilename) + 1;
+       const char *state_string = "";
+
+       flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message);
+
+       flac__utils_printf(stderr, 1, "%*s init_status = %s\n", ilen, "", FLAC__StreamEncoderInitStatusString[init_status]);
+
+       if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR) {
+               state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder);
+
+               flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string);
+
+               /* print out some more info for some errors: */
+               if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) {
+                       flac__utils_printf(stderr, 1,
+                               "\n"
+                               "An error occurred while writing; the most common cause is that the disk is full.\n"
+                       );
+               }
+               else if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_IO_ERROR])) {
+                       flac__utils_printf(stderr, 1,
+                               "\n"
+                               "An error occurred opening the output file; it is likely that the output\n"
+                               "directory does not exist or is not writable, the output file already exists and\n"
+                               "is not writable, or the disk is full.\n"
+                       );
+               }
+       }
+       else if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE) {
+               flac__utils_printf(stderr, 1,
+                       "\n"
+                       "The encoding parameters specified do not conform to the FLAC Subset and may not\n"
+                       "be streamable or playable in hardware devices.  If you really understand the\n"
+                       "consequences, you can add --lax to the command-line options to encode with\n"
+                       "these parameters anyway.  See http://flac.sourceforge.net/format.html#subset\n"
+               );
+       }
+}
+
+void print_error_with_state(const EncoderSession *e, const char *message)
+{
+       const int ilen = strlen(e->inbasefilename) + 1;
+       const char *state_string;
+
+       flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message);
+
+       state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder);
+
+       flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string);
+
+       /* print out some more info for some errors: */
+       if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) {
+               flac__utils_printf(stderr, 1,
+                       "\n"
+                       "An error occurred while writing; the most common cause is that the disk is full.\n"
+               );
+       }
+}
+
+void print_verify_error(EncoderSession *e)
+{
+       FLAC__uint64 absolute_sample;
+       unsigned frame_number;
+       unsigned channel;
+       unsigned sample;
+       FLAC__int32 expected;
+       FLAC__int32 got;
+
+       FLAC__stream_encoder_get_verify_decoder_error_stats(e->encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+
+       flac__utils_printf(stderr, 1, "%s: ERROR: mismatch in decoded data, verify FAILED!\n", e->inbasefilename);
+       flac__utils_printf(stderr, 1, "       Absolute sample=%u, frame=%u, channel=%u, sample=%u, expected %d, got %d\n", (unsigned)absolute_sample, frame_number, channel, sample, expected, got);
+       flac__utils_printf(stderr, 1, "       In all known cases, verify errors are caused by hardware problems,\n");
+       flac__utils_printf(stderr, 1, "       usually overclocking or bad RAM.  Delete %s\n", e->outfilename);
+       flac__utils_printf(stderr, 1, "       and repeat the flac command exactly as before.  If it does not give a\n");
+       flac__utils_printf(stderr, 1, "       verify error in the exact same place each time you try it, then there is\n");
+       flac__utils_printf(stderr, 1, "       a problem with your hardware; please see the FAQ:\n");
+       flac__utils_printf(stderr, 1, "           http://flac.sourceforge.net/faq.html#tools__hardware_prob\n");
+       flac__utils_printf(stderr, 1, "       If it does fail in the exact same place every time, keep\n");
+       flac__utils_printf(stderr, 1, "       %s and submit a bug report to:\n", e->outfilename);
+       flac__utils_printf(stderr, 1, "           https://sourceforge.net/bugs/?func=addbug&group_id=13478\n");
+       flac__utils_printf(stderr, 1, "       Make sure to upload the FLAC file and use the \"Monitor\" feature to\n");
+       flac__utils_printf(stderr, 1, "       monitor the bug status.\n");
+       flac__utils_printf(stderr, 1, "Verify FAILED!  Do not trust %s\n", e->outfilename);
+}
+
+FLAC__bool read_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn)
+{
+       size_t bytes_read = fread(val, 1, 2, f);
+
+       if(bytes_read == 0) {
+               if(!eof_ok) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+                       return false;
+               }
+               else
+                       return true;
+       }
+       else if(bytes_read < 2) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+               return false;
+       }
+       else {
+               if(is_big_endian_host_) {
+                       FLAC__byte tmp, *b = (FLAC__byte*)val;
+                       tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+               }
+               return true;
+       }
+}
+
+FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn)
+{
+       size_t bytes_read = fread(val, 1, 4, f);
+
+       if(bytes_read == 0) {
+               if(!eof_ok) {
+                       flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+                       return false;
+               }
+               else
+                       return true;
+       }
+       else if(bytes_read < 4) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+               return false;
+       }
+       else {
+               if(is_big_endian_host_) {
+                       FLAC__byte tmp, *b = (FLAC__byte*)val;
+                       tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+                       tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+               }
+               return true;
+       }
+}
+
+FLAC__bool read_big_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn)
+{
+       unsigned char buf[4];
+       size_t bytes_read= fread(buf, 1, 2, f);
+
+       if(bytes_read==0U && eof_ok)
+               return true;
+       else if(bytes_read<2U) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+               return false;
+       }
+
+       /* this is independent of host endianness */
+       *val= (FLAC__uint16)(buf[0])<<8 | buf[1];
+
+       return true;
+}
+
+FLAC__bool read_big_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn)
+{
+       unsigned char buf[4];
+       size_t bytes_read= fread(buf, 1, 4, f);
+
+       if(bytes_read==0U && eof_ok)
+               return true;
+       else if(bytes_read<4U) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+               return false;
+       }
+
+       /* this is independent of host endianness */
+       *val= (FLAC__uint32)(buf[0])<<24 | (FLAC__uint32)(buf[1])<<16 |
+               (FLAC__uint32)(buf[2])<<8 | buf[3];
+
+       return true;
+}
+
+FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn)
+       /* Read an IEEE 754 80-bit (aka SANE) extended floating point value from 'f',
+        * convert it into an integral value and store in 'val'.  Return false if only
+        * between 1 and 9 bytes remain in 'f', if 0 bytes remain in 'f' and 'eof_ok' is
+        * false, or if the value is negative, between zero and one, or too large to be
+        * represented by 'val'; return true otherwise.
+        */
+{
+       unsigned int i;
+       unsigned char buf[10];
+       size_t bytes_read= fread(buf, 1U, 10U, f);
+       FLAC__int16 e= ((FLAC__uint16)(buf[0])<<8 | (FLAC__uint16)(buf[1]))-0x3FFF;
+       FLAC__int16 shift= 63-e;
+       FLAC__uint64 p= 0U;
+
+       if(bytes_read==0U && eof_ok)
+               return true;
+       else if(bytes_read<10U) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+               return false;
+       }
+       else if((buf[0]>>7)==1U || e<0 || e>63) {
+               flac__utils_printf(stderr, 1, "%s: ERROR: invalid floating-point value\n", fn);
+               return false;
+       }
+
+       for(i= 0U; i<8U; ++i)
+               p|= (FLAC__uint64)(buf[i+2])<<(56U-i*8);
+       *val= (FLAC__uint32)((p>>shift)+(p>>(shift-1) & 0x1));
+
+       return true;
+}
+
+FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset)
+{
+       static unsigned char dump[8192];
+
+#ifdef _MSC_VER
+       if(f == stdin) {
+               /* MS' stdio impl can't even seek forward on stdin, have to use pure non-fseek() version: */
+               while(offset > 0) {
+                       const long need = (long)min(offset, sizeof(dump));
+                       if((long)fread(dump, 1, need, f) < need)
+                               return false;
+                       offset -= need;
+               }
+       }
+       else
+#endif
+       {
+               while(offset > 0) {
+                       long need = (long)min(offset, LONG_MAX);
+                       if(fseeko(f, need, SEEK_CUR) < 0) {
+                               need = (long)min(offset, sizeof(dump));
+                               if((long)fread(dump, 1, need, f) < need)
+                                       return false;
+                       }
+                       offset -= need;
+               }
+       }
+       return true;
+}
+
+unsigned count_channel_mask_bits(FLAC__uint32 mask)
+{
+       unsigned count = 0;
+       while(mask) {
+               if(mask & 1)
+                       count++;
+               mask >>= 1;
+       }
+       return count;
+}
+
+#if 0
+FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, unsigned channels)
+{
+       FLAC__uint32 x = 0x80000000;
+       unsigned count = count_channel_mask_bits(mask);
+       while(x && count > channels) {
+               if(mask & x) {
+                       mask &= ~x;
+                       count--;
+               }
+               x >>= 1;
+       }
+       FLAC__ASSERT(count_channel_mask_bits(mask) == channels);
+       return mask;
+}
+#endif
diff --git a/src/flac/encode.h b/src/flac/encode.h
new file mode 100644 (file)
index 0000000..13ee7d3
--- /dev/null
@@ -0,0 +1,122 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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__encode_h
+#define flac__encode_h
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "foreign_metadata.h"
+#include "utils.h"
+
+extern const int FLAC_ENCODE__DEFAULT_PADDING;
+
+typedef enum {
+       CST_BLOCKSIZE,
+       CST_COMPRESSION_LEVEL,
+       CST_DO_MID_SIDE,
+       CST_LOOSE_MID_SIDE,
+       CST_APODIZATION,
+       CST_MAX_LPC_ORDER,
+       CST_QLP_COEFF_PRECISION,
+       CST_DO_QLP_COEFF_PREC_SEARCH,
+       CST_DO_ESCAPE_CODING,
+       CST_DO_EXHAUSTIVE_MODEL_SEARCH,
+       CST_MIN_RESIDUAL_PARTITION_ORDER,
+       CST_MAX_RESIDUAL_PARTITION_ORDER,
+       CST_RICE_PARAMETER_SEARCH_DIST
+} compression_setting_type_t;
+
+typedef struct {
+       compression_setting_type_t type;
+       union {
+               FLAC__bool t_bool;
+               unsigned t_unsigned;
+               const char *t_string;
+       } value;
+} compression_setting_t;
+
+typedef struct {
+       utils__SkipUntilSpecification skip_specification;
+       utils__SkipUntilSpecification until_specification;
+       FLAC__bool verify;
+#if FLAC__HAS_OGG
+       FLAC__bool use_ogg;
+       long serial_number;
+#endif
+       FLAC__bool lax;
+       int padding;
+       size_t num_compression_settings;
+       compression_setting_t compression_settings[64];
+       char *requested_seek_points;
+       int num_requested_seek_points;
+       const char *cuesheet_filename;
+       FLAC__bool treat_warnings_as_errors;
+       FLAC__bool continue_through_decode_errors; /* currently only obeyed when encoding from FLAC or Ogg FLAC */
+       FLAC__bool cued_seekpoints;
+       FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+
+       /* options related to --replay-gain and --sector-align */
+       FLAC__bool is_first_file;
+       FLAC__bool is_last_file;
+       FLAC__int32 **align_reservoir;
+       unsigned *align_reservoir_samples;
+       FLAC__bool replay_gain;
+       FLAC__bool ignore_chunk_sizes;
+       FLAC__bool sector_align;
+
+       FLAC__StreamMetadata *vorbis_comment;
+       FLAC__StreamMetadata *pictures[64];
+       unsigned num_pictures;
+
+       struct {
+               FLAC__bool disable_constant_subframes;
+               FLAC__bool disable_fixed_subframes;
+               FLAC__bool disable_verbatim_subframes;
+               FLAC__bool do_md5;
+       } debug;
+} encode_options_t;
+
+typedef struct {
+       encode_options_t common;
+       foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+} wav_encode_options_t;
+
+typedef struct {
+       encode_options_t common;
+
+       FLAC__bool is_big_endian;
+       FLAC__bool is_unsigned_samples;
+       unsigned channels;
+       unsigned bps;
+       unsigned sample_rate;
+} raw_encode_options_t;
+
+typedef struct {
+       encode_options_t common;
+} flac_encode_options_t;
+
+int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options, FLAC__bool is_aifc);
+int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options);
+int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options);
+int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options, FLAC__bool input_is_ogg);
+
+#endif
diff --git a/src/flac/flac.dsp b/src/flac/flac.dsp
new file mode 100644 (file)
index 0000000..fbf1000
--- /dev/null
@@ -0,0 +1,156 @@
+# Microsoft Developer Studio Project File - Name="flac" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=flac - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac.mak" CFG="flac - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "flac - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "flac - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "flac - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\obj\release\lib\replaygain_synthesis_static.lib ..\..\obj\release\lib\getopt_static.lib ..\..\obj\release\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "flac - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\grabbag_static.lib ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\obj\debug\lib\replaygain_synthesis_static.lib ..\..\obj\debug\lib\getopt_static.lib ..\..\obj\debug\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "flac - Win32 Release"\r
+# Name "flac - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\analyze.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\decode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\foreign_metadata.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\local_string_utils.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utils.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vorbiscomment.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\analyze.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\decode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\foreign_metadata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\local_string_utils.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utils.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vorbiscomment.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/flac/flac.vcproj b/src/flac/flac.vcproj
new file mode 100644 (file)
index 0000000..050a161
--- /dev/null
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="flac"\r
+       ProjectGUID="{4cefbc7d-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="flac"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\analyze.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\decode.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encode.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\foreign_metadata.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\local_string_utils.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\utils.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\vorbiscomment.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\analyze.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\decode.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encode.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\foreign_metadata.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\local_string_utils.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\utils.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\vorbiscomment.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c
new file mode 100644 (file)
index 0000000..3fc5310
--- /dev/null
@@ -0,0 +1,588 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include <stdio.h> /* for FILE etc. */
+#include <stdlib.h> /* for calloc() etc. */
+#include <string.h> /* for memcmp() etc. */
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+#include "foreign_metadata.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+
+static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[2] = { "aiff" , "riff" };
+
+static FLAC__uint32 unpack32be_(const FLAC__byte *b)
+{
+       return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
+}
+
+static FLAC__uint32 unpack32le_(const FLAC__byte *b)
+{
+       return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
+}
+
+static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error)
+{
+       static FLAC__byte buffer[4096];
+       size_t left;
+       for(left = size; left > 0; ) {
+               size_t need = min(sizeof(buffer), left);
+               if(fread(buffer, 1, need, fin) < need) {
+                       if(error) *error = read_error;
+                       return false;
+               }
+               if(fwrite(buffer, 1, need, fout) < need) {
+                       if(error) *error = write_error;
+                       return false;
+               }
+               left -= need;
+       }
+       return true;
+}
+
+static FLAC__bool append_block_(foreign_metadata_t *fm, off_t offset, FLAC__uint32 size, const char **error)
+{
+       foreign_block_t *fb = safe_realloc_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/);
+       if(fb) {
+               fb[fm->num_blocks].offset = offset;
+               fb[fm->num_blocks].size = size;
+               fm->num_blocks++;
+               fm->blocks = fb;
+               return true;
+       }
+       if(error) *error = "out of memory";
+       return false;
+}
+
+static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+       FLAC__byte buffer[12];
+       off_t offset, eof_offset;
+       if((offset = ftello(f)) < 0) {
+               if(error) *error = "ftello() error (001)";
+               return false;
+       }
+       if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) {
+               if(error) *error = "unsupported FORM layout (002)";
+               return false;
+       }
+       if(!append_block_(fm, offset, 12, error))
+               return false;
+       eof_offset = 8 + unpack32be_(buffer+4);
+       while(!feof(f)) {
+               FLAC__uint32 size;
+               if((offset = ftello(f)) < 0) {
+                       if(error) *error = "ftello() error (003)";
+                       return false;
+               }
+               if((size = fread(buffer, 1, 8, f)) < 8) {
+                       if(size == 0 && feof(f))
+                               break;
+                       if(error) *error = "invalid AIFF file (004)";
+                       return false;
+               }
+               size = unpack32be_(buffer+4);
+               /* check if pad byte needed */
+               if(size & 1)
+                       size++;
+               if(!memcmp(buffer, "COMM", 4)) {
+                       if(fm->format_block) {
+                               if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)";
+                               return false;
+                       }
+                       if(fm->audio_block) {
+                               if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)";
+                               return false;
+                       }
+                       fm->format_block = fm->num_blocks;
+               }
+               else if(!memcmp(buffer, "SSND", 4)) {
+                       if(fm->audio_block) {
+                               if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)";
+                               return false;
+                       }
+                       if(!fm->format_block) {
+                               if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)";
+                               return false;
+                       }
+                       fm->audio_block = fm->num_blocks;
+                       /* read #offset bytes */
+                       if(fread(buffer+8, 1, 4, f) < 4) {
+                               if(error) *error = "invalid AIFF file (009)";
+                               return false;
+                       }
+                       fm->ssnd_offset_size = unpack32be_(buffer+8);
+                       if(fseeko(f, -4, SEEK_CUR) < 0) {
+                               if(error) *error = "invalid AIFF file: seek error (010)";
+                               return false;
+                       }
+               }
+               if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
+                       return false;
+               if(fseeko(f, size, SEEK_CUR) < 0) {
+                       if(error) *error = "invalid AIFF file: seek error (011)";
+                       return false;
+               }
+       }
+       if(eof_offset != ftello(f)) {
+               if(error) *error = "invalid AIFF file: unexpected EOF (012)";
+               return false;
+       }
+       if(!fm->format_block) {
+               if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)";
+               return false;
+       }
+       if(!fm->audio_block) {
+               if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)";
+               return false;
+       }
+       return true;
+}
+
+static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+       FLAC__byte buffer[12];
+       off_t offset, eof_offset;
+       if((offset = ftello(f)) < 0) {
+               if(error) *error = "ftello() error (001)";
+               return false;
+       }
+       if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "RIFF", 4) || memcmp(buffer+8, "WAVE", 4)) {
+               if(error) *error = "unsupported RIFF layout (002)";
+               return false;
+       }
+       if(!append_block_(fm, offset, 12, error))
+               return false;
+       eof_offset = 8 + unpack32le_(buffer+4);
+       while(!feof(f)) {
+               FLAC__uint32 size;
+               if((offset = ftello(f)) < 0) {
+                       if(error) *error = "ftello() error (003)";
+                       return false;
+               }
+               if((size = fread(buffer, 1, 8, f)) < 8) {
+                       if(size == 0 && feof(f))
+                               break;
+                       if(error) *error = "invalid WAVE file (004)";
+                       return false;
+               }
+               size = unpack32le_(buffer+4);
+               /* check if pad byte needed */
+               if(size & 1)
+                       size++;
+               if(!memcmp(buffer, "fmt ", 4)) {
+                       if(fm->format_block) {
+                               if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)";
+                               return false;
+                       }
+                       if(fm->audio_block) {
+                               if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)";
+                               return false;
+                       }
+                       fm->format_block = fm->num_blocks;
+               }
+               else if(!memcmp(buffer, "data", 4)) {
+                       if(fm->audio_block) {
+                               if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)";
+                               return false;
+                       }
+                       if(!fm->format_block) {
+                               if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)";
+                               return false;
+                       }
+                       fm->audio_block = fm->num_blocks;
+               }
+               if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
+                       return false;
+               if(fseeko(f, size, SEEK_CUR) < 0) {
+                       if(error) *error = "invalid WAVE file: seek error (009)";
+                       return false;
+               }
+       }
+       if(eof_offset != ftello(f)) {
+               if(error) *error = "invalid WAVE file: unexpected EOF (010)";
+               return false;
+       }
+       if(!fm->format_block) {
+               if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)";
+               return false;
+       }
+       if(!fm->audio_block) {
+               if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)";
+               return false;
+       }
+       return true;
+}
+
+static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
+{
+       FLAC__byte buffer[4];
+       const unsigned ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+       size_t block_num = 0;
+       FLAC__ASSERT(sizeof(buffer) >= ID_LEN);
+       while(block_num < fm->num_blocks) {
+               /* find next matching padding block */
+               do {
+                       /* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */
+                       if(!FLAC__metadata_simple_iterator_next(it)) {
+                               if(error) *error = "no matching PADDING block found (004)";
+                               return false;
+                       }
+               } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING);
+               if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) {
+                       if(error) *error = "PADDING block with wrong size found (005)";
+                       return false;
+               }
+               /* transfer chunk into APPLICATION block */
+               /* first set up the file pointers */
+               if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) {
+                       if(error) *error = "seek failed in WAVE/AIFF file (006)";
+                       return false;
+               }
+               if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) {
+                       if(error) *error = "seek failed in FLAC file (007)";
+                       return false;
+               }
+               /* update the type */
+               buffer[0] = FLAC__METADATA_TYPE_APPLICATION;
+               if(FLAC__metadata_simple_iterator_is_last(it))
+                       buffer[0] |= 0x80; /*MAGIC number*/
+               if(fwrite(buffer, 1, 1, fout) < 1) {
+                       if(error) *error = "write failed in FLAC file (008)";
+                       return false;
+               }
+               /* length stays the same so skip over it */
+               if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) {
+                       if(error) *error = "seek failed in FLAC file (009)";
+                       return false;
+               }
+               /* write the APPLICATION ID */
+               memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN);
+               if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) {
+                       if(error) *error = "write failed in FLAC file (010)";
+                       return false;
+               }
+               /* transfer the foreign metadata */
+               if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)"))
+                       return false;
+               block_num++;
+       }
+       return true;
+}
+
+static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error)
+{
+       FLAC__byte id[4], buffer[12];
+       off_t offset;
+       FLAC__bool type_found = false;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
+
+       while(FLAC__metadata_simple_iterator_next(it)) {
+               if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
+                       continue;
+               if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
+                       if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (003)";
+                       return false;
+               }
+               if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
+                       continue;
+               offset = FLAC__metadata_simple_iterator_get_block_offset(it);
+               /* skip over header and app ID */
+               offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
+               offset += sizeof(id);
+               /* look for format or audio blocks */
+               if(fseek(f, offset, SEEK_SET) < 0) {
+                       if(error) *error = "seek error (004)";
+                       return false;
+               }
+               if(fread(buffer, 1, 4, f) != 4) {
+                       if(error) *error = "read error (005)";
+                       return false;
+               }
+               if(fm->num_blocks == 0) {
+                       if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && 0 == memcmp(buffer, "RIFF", 4))
+                               type_found = true;
+                       else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
+                               type_found = true;
+                       else {
+                               if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)";
+                               return false;
+                       }
+               }
+               else if(!type_found) {
+                       FLAC__ASSERT(0);
+                       /* double protection: */
+                       if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)";
+                       return false;
+               }
+               else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) {
+                       if(!memcmp(buffer, "fmt ", 4)) {
+                               if(fm->format_block) {
+                                       if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)";
+                                       return false;
+                               }
+                               if(fm->audio_block) {
+                                       if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)";
+                                       return false;
+                               }
+                               fm->format_block = fm->num_blocks;
+                       }
+                       else if(!memcmp(buffer, "data", 4)) {
+                               if(fm->audio_block) {
+                                       if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)";
+                                       return false;
+                               }
+                               if(!fm->format_block) {
+                                       if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)";
+                                       return false;
+                               }
+                               fm->audio_block = fm->num_blocks;
+                       }
+               }
+               else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
+                       if(!memcmp(buffer, "COMM", 4)) {
+                               if(fm->format_block) {
+                                       if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (011)";
+                                       return false;
+                               }
+                               if(fm->audio_block) {
+                                       if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (012)";
+                                       return false;
+                               }
+                               fm->format_block = fm->num_blocks;
+                       }
+                       else if(!memcmp(buffer, "SSND", 4)) {
+                               if(fm->audio_block) {
+                                       if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (013)";
+                                       return false;
+                               }
+                               if(!fm->format_block) {
+                                       if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (014)";
+                                       return false;
+                               }
+                               fm->audio_block = fm->num_blocks;
+                               /* read SSND offset size */
+                               if(fread(buffer+4, 1, 8, f) != 8) {
+                                       if(error) *error = "read error (015)";
+                                       return false;
+                               }
+                               fm->ssnd_offset_size = unpack32be_(buffer+8);
+                       }
+               }
+               else {
+                       FLAC__ASSERT(0);
+                       /* double protection: */
+                       if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (016)";
+                       return false;
+               }
+               if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
+                       return false;
+       }
+       if(!type_found) {
+               if(error) *error = "no foreign metadata found (017)";
+               return false;
+       }
+       if(!fm->format_block) {
+               if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (018)" : "invalid AIFF file: missing \"COMM\" chunk (018)";
+               return false;
+       }
+       if(!fm->audio_block) {
+               if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (019)" : "invalid AIFF file: missing \"SSND\" chunk (019)";
+               return false;
+       }
+       return true;
+}
+
+static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, off_t offset1, off_t offset2, off_t offset3, const char **error)
+{
+       size_t i;
+       if(fseeko(fout, offset1, SEEK_SET) < 0) {
+               if(error) *error = "seek failed in WAVE/AIFF file (002)";
+               return false;
+       }
+       for(i = 1; i < fm->format_block; i++) {
+               if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+                       if(error) *error = "seek failed in FLAC file (003)";
+                       return false;
+               }
+               if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)"))
+                       return false;
+       }
+       if(fseeko(fout, offset2, SEEK_SET) < 0) {
+               if(error) *error = "seek failed in WAVE/AIFF file (006)";
+               return false;
+       }
+       for(i = fm->format_block+1; i < fm->audio_block; i++) {
+               if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+                       if(error) *error = "seek failed in FLAC file (007)";
+                       return false;
+               }
+               if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)"))
+                       return false;
+       }
+       if(fseeko(fout, offset3, SEEK_SET) < 0) {
+               if(error) *error = "seek failed in WAVE/AIFF file (010)";
+               return false;
+       }
+       for(i = fm->audio_block+1; i < fm->num_blocks; i++) {
+               if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+                       if(error) *error = "seek failed in FLAC file (011)";
+                       return false;
+               }
+               if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)"))
+                       return false;
+       }
+       return true;
+}
+
+foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
+{
+       foreign_metadata_t *x = (foreign_metadata_t*)calloc(sizeof(foreign_metadata_t), 1);
+       if(x)
+               x->type = type;
+       return x;
+}
+
+void flac__foreign_metadata_delete(foreign_metadata_t *fm)
+{
+       if(fm) {
+               if(fm->blocks)
+                       free(fm->blocks);
+               free(fm);
+       }
+}
+
+FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+       FLAC__bool ok;
+       FILE *f = fopen(filename, "rb");
+       if(!f) {
+               if(error) *error = "can't open AIFF file for reading (000)";
+               return false;
+       }
+       ok = read_from_aiff_(fm, f, error);
+       fclose(f);
+       return ok;
+}
+
+FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+       FLAC__bool ok;
+       FILE *f = fopen(filename, "rb");
+       if(!f) {
+               if(error) *error = "can't open WAVE file for reading (000)";
+               return false;
+       }
+       ok = read_from_wave_(fm, f, error);
+       fclose(f);
+       return ok;
+}
+
+FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
+{
+       FLAC__bool ok;
+       FILE *fin, *fout;
+       FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
+       if(!it) {
+               if(error) *error = "out of memory (000)";
+               return false;
+       }
+       if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
+               if(error) *error = "can't initialize iterator (001)";
+               FLAC__metadata_simple_iterator_delete(it);
+               return false;
+       }
+       if(0 == (fin = fopen(infilename, "rb"))) {
+               if(error) *error = "can't open WAVE/AIFF file for reading (002)";
+               FLAC__metadata_simple_iterator_delete(it);
+               return false;
+       }
+       if(0 == (fout = fopen(outfilename, "r+b"))) {
+               if(error) *error = "can't open FLAC file for updating (003)";
+               FLAC__metadata_simple_iterator_delete(it);
+               fclose(fin);
+               return false;
+       }
+       ok = write_to_flac_(fm, fin, fout, it, error);
+       FLAC__metadata_simple_iterator_delete(it);
+       fclose(fin);
+       fclose(fout);
+       return ok;
+}
+
+FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+       FLAC__bool ok;
+       FILE *f;
+       FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new();
+       if(!it) {
+               if(error) *error = "out of memory (000)";
+               return false;
+       }
+       if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) {
+               if(error) *error = "can't initialize iterator (001)";
+               FLAC__metadata_simple_iterator_delete(it);
+               return false;
+       }
+       if(0 == (f = fopen(filename, "rb"))) {
+               if(error) *error = "can't open FLAC file for reading (002)";
+               FLAC__metadata_simple_iterator_delete(it);
+               return false;
+       }
+       ok = read_from_flac_(fm, f, it, error);
+       FLAC__metadata_simple_iterator_delete(it);
+       fclose(f);
+       return ok;
+}
+
+FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, off_t offset1, off_t offset2, off_t offset3, const char **error)
+{
+       FLAC__bool ok;
+       FILE *fin, *fout;
+       if(0 == (fin = fopen(infilename, "rb"))) {
+               if(error) *error = "can't open FLAC file for reading (000)";
+               return false;
+       }
+       if(0 == (fout = fopen(outfilename, "r+b"))) {
+               if(error) *error = "can't open WAVE/AIFF file for updating (001)";
+               fclose(fin);
+               return false;
+       }
+       ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error);
+       fclose(fin);
+       fclose(fout);
+       return ok;
+}
diff --git a/src/flac/foreign_metadata.h b/src/flac/foreign_metadata.h
new file mode 100644 (file)
index 0000000..baeda20
--- /dev/null
@@ -0,0 +1,59 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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__foreign_metadata_h
+#define flac__foreign_metadata_h
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "utils.h"
+
+/* WATCHOUT: these enums are used to index internal arrays */
+typedef enum { FOREIGN_BLOCK_TYPE__AIFF = 0, FOREIGN_BLOCK_TYPE__RIFF = 1 } foreign_block_type_t;
+
+typedef struct {
+       /* for encoding, this will be the offset in the WAVE/AIFF file of the chunk */
+       /* for decoding, this will be the offset in the FLAC file of the chunk data inside the APPLICATION block */
+       off_t offset;
+       FLAC__uint32 size;
+} foreign_block_t;
+
+typedef struct {
+       foreign_block_type_t type; /* currently we don't support multiple foreign types in a stream (an maybe never will) */
+       foreign_block_t *blocks;
+       size_t num_blocks;
+       size_t format_block; /* block number of 'fmt ' or 'COMM' chunk */
+       size_t audio_block; /* block number of 'data' or 'SSND' chunk */
+       FLAC__uint32 ssnd_offset_size; /* 0 if type!=AIFF */
+} foreign_metadata_t;
+
+foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type);
+
+void flac__foreign_metadata_delete(foreign_metadata_t *fm);
+
+FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error);
+
+FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error);
+FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, off_t offset1, off_t offset2, off_t offset3, const char **error);
+
+#endif
diff --git a/src/flac/iffscan.c b/src/flac/iffscan.c
new file mode 100644 (file)
index 0000000..d03b65b
--- /dev/null
@@ -0,0 +1,112 @@
+/* iffscan - Simple AIFF/RIFF chunk scanner
+ * Copyright (C) 2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "foreign_metadata.h"
+
+static FLAC__uint32 unpack32be_(const FLAC__byte *b)
+{
+       return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3];
+}
+
+static FLAC__uint32 unpack32le_(const FLAC__byte *b)
+{
+       return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24);
+}
+
+static FLAC__uint32 unpack32_(const FLAC__byte *b, foreign_block_type_t type)
+{
+       if(type == FOREIGN_BLOCK_TYPE__AIFF)
+               return unpack32be_(b);
+       else
+               return unpack32le_(b);
+}
+
+int main(int argc, char *argv[])
+{
+       FILE *f;
+       char buf[12];
+       foreign_metadata_t *fm;
+       const char *fn, *error;
+       size_t i;
+       FLAC__uint32 size;
+
+       if(argc != 2) {
+               fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]);
+               return 1;
+       }
+       fn = argv[1];
+       if(0 == (f = fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) {
+               fprintf(stderr, "ERROR opening %s for reading\n", fn);
+               return 1;
+       }
+       fclose(f);
+       if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
+               fprintf(stderr, "ERROR: out of memory\n");
+               return 1;
+       }
+       if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
+               if(!flac__foreign_metadata_read_from_aiff(fm, fn, &error)) {
+                       fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+                       return 1;
+               }
+       }
+       else {
+               if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) {
+                       fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+                       return 1;
+               }
+       }
+       if(0 == (f = fopen(fn, "rb"))) {
+               fprintf(stderr, "ERROR opening %s for reading\n", fn);
+               return 1;
+       }
+       for(i = 0; i < fm->num_blocks; i++) {
+               if(fseeko(f, fm->blocks[i].offset, SEEK_SET) < 0) {
+                       fprintf(stderr, "ERROR seeking in %s\n", fn);
+                       return 1;
+               }
+               if(fread(buf, 1, 12, f) != 12) {
+                       fprintf(stderr, "ERROR reading %s\n", fn);
+                       return 1;
+               }
+               size = unpack32_((const FLAC__byte*)buf+4, fm->type);
+               printf("block:[%c%c%c%c] size=%08x=(%10u)", buf[0], buf[1], buf[2], buf[3], size, size);
+               if(i == 0)
+                       printf(" type:[%c%c%c%c]", buf[8], buf[9], buf[10], buf[11]);
+               else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && i == fm->audio_block)
+                       printf(" offset size=%08x=(%10u)", fm->ssnd_offset_size, fm->ssnd_offset_size);
+               printf("\n");
+       }
+       fclose(f);
+       flac__foreign_metadata_delete(fm);
+       return 0;
+}
diff --git a/src/flac/iffscan.dsp b/src/flac/iffscan.dsp
new file mode 100644 (file)
index 0000000..9a21ffb
--- /dev/null
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="iffscan" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=iffscan - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "iffscan.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "iffscan.mak" CFG="iffscan - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "iffscan - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "iffscan - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "iffscan - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "iffscan - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "iffscan - Win32 Release"\r
+# Name "iffscan - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\iffscan.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\foreign_metadata.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\foreign_metadata.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/flac/iffscan.vcproj b/src/flac/iffscan.vcproj
new file mode 100644 (file)
index 0000000..926cb9d
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="iffscan"\r
+       ProjectGUID="{4cefbc94-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="iffscan"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-6E5FBE522BFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\foreign_metadata.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2D32A752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\foreign_metadata.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\iffscan.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/flac/local_string_utils.c b/src/flac/local_string_utils.c
new file mode 100644 (file)
index 0000000..d0f8ed3
--- /dev/null
@@ -0,0 +1,109 @@
+/* flac - Command-line FLAC encoder/decoder
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include "utils.h"
+#include "local_string_utils.h"
+
+/*     $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+flac__strlcpy(char *dst, const char *src, size_t siz)
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return(s - src - 1);    /* count does not include NUL */
+}
+
+/*     $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+flac__strlcat(char *dst, const char *src, size_t siz)
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return(dlen + (s - src));       /* count does not include NUL */
+}
diff --git a/src/flac/local_string_utils.h b/src/flac/local_string_utils.h
new file mode 100644 (file)
index 0000000..e43041b
--- /dev/null
@@ -0,0 +1,27 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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__local_string_utils_h
+#define flac__local_string_utils_h
+
+#include <stdlib.h> /* for size_t */
+
+size_t flac__strlcpy(char *dst, const char *src, size_t siz);
+size_t flac__strlcat(char *dst, const char *src, size_t siz);
+
+#endif
diff --git a/src/flac/main.c b/src/flac/main.c
new file mode 100644 (file)
index 0000000..f3716a8
--- /dev/null
@@ -0,0 +1,2181 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if !defined _MSC_VER && !defined __MINGW32__
+/* unlink is in stdio.h in VC++ */
+#include <unistd.h> /* for unlink() */
+#endif
+#include "FLAC/all.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "analyze.h"
+#include "decode.h"
+#include "encode.h"
+#include "local_string_utils.h" /* for flac__strlcat() and flac__strlcpy() */
+#include "utils.h"
+#include "vorbiscomment.h"
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+#define FLAC__STRCASECMP stricmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#endif
+
+#if 0
+/*[JEC] was:#if HAVE_GETOPT_LONG*/
+/*[JEC] see flac/include/share/getopt.h as to why the change */
+#  include <getopt.h>
+#else
+#  include "share/getopt.h"
+#endif
+
+typedef enum { RAW, WAV, AIF, FLAC, OGGFLAC } FileFormat;
+
+static int do_it(void);
+
+static FLAC__bool init_options(void);
+static int parse_options(int argc, char *argv[]);
+static int parse_option(int short_option, const char *long_option, const char *option_argument);
+static void free_options(void);
+static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value);
+static void add_compression_setting_string(compression_setting_type_t type, const char *value);
+static void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value);
+
+static int usage_error(const char *message, ...);
+static void short_usage(void);
+static void show_version(void);
+static void show_help(void);
+static void show_explain(void);
+static void format_mistake(const char *infilename, FileFormat wrong, FileFormat right);
+
+static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file);
+static int decode_file(const char *infilename);
+
+static const char *get_encoded_outfilename(const char *infilename);
+static const char *get_decoded_outfilename(const char *infilename);
+static const char *get_outfilename(const char *infilename, const char *suffix);
+
+static void die(const char *message);
+static int conditional_fclose(FILE *f);
+static char *local_strdup(const char *source);
+#ifdef _MSC_VER
+/* There's no strtoll() in MSVC6 so we just write a specialized one */
+static FLAC__int64 local__strtoll(const char *src, char **endptr);
+#endif
+
+
+/*
+ * share__getopt format struct; note that for long options with no
+ * short option equivalent we just set the 'val' field to 0.
+ */
+static struct share__option long_options_[] = {
+       /*
+        * general options
+        */
+       { "help"                  , share__no_argument, 0, 'h' },
+       { "explain"               , share__no_argument, 0, 'H' },
+       { "version"               , share__no_argument, 0, 'v' },
+       { "decode"                , share__no_argument, 0, 'd' },
+       { "analyze"               , share__no_argument, 0, 'a' },
+       { "test"                  , share__no_argument, 0, 't' },
+       { "stdout"                , share__no_argument, 0, 'c' },
+       { "silent"                , share__no_argument, 0, 's' },
+       { "totally-silent"        , share__no_argument, 0, 0 },
+       { "warnings-as-errors"    , share__no_argument, 0, 'w' },
+       { "force"                 , share__no_argument, 0, 'f' },
+       { "delete-input-file"     , share__no_argument, 0, 0 },
+       { "keep-foreign-metadata" , share__no_argument, 0, 0 },
+       { "output-prefix"         , share__required_argument, 0, 0 },
+       { "output-name"           , share__required_argument, 0, 'o' },
+       { "skip"                  , share__required_argument, 0, 0 },
+       { "until"                 , share__required_argument, 0, 0 },
+       { "channel-map"           , share__required_argument, 0, 0 }, /* undocumented */
+
+       /*
+        * decoding options
+        */
+       { "decode-through-errors", share__no_argument, 0, 'F' },
+       { "cue"                  , share__required_argument, 0, 0 },
+       { "apply-replaygain-which-is-not-lossless", share__optional_argument, 0, 0 }, /* undocumented */
+
+       /*
+        * encoding options
+        */
+       { "cuesheet"                  , share__required_argument, 0, 0 },
+       { "no-cued-seekpoints"        , share__no_argument, 0, 0 },
+       { "picture"                   , share__required_argument, 0, 0 },
+       { "tag"                       , share__required_argument, 0, 'T' },
+       { "tag-from-file"             , share__required_argument, 0, 0 },
+       { "compression-level-0"       , share__no_argument, 0, '0' },
+       { "compression-level-1"       , share__no_argument, 0, '1' },
+       { "compression-level-2"       , share__no_argument, 0, '2' },
+       { "compression-level-3"       , share__no_argument, 0, '3' },
+       { "compression-level-4"       , share__no_argument, 0, '4' },
+       { "compression-level-5"       , share__no_argument, 0, '5' },
+       { "compression-level-6"       , share__no_argument, 0, '6' },
+       { "compression-level-7"       , share__no_argument, 0, '7' },
+       { "compression-level-8"       , share__no_argument, 0, '8' },
+       { "compression-level-9"       , share__no_argument, 0, '9' },
+       { "best"                      , share__no_argument, 0, '8' },
+       { "fast"                      , share__no_argument, 0, '0' },
+       { "verify"                    , share__no_argument, 0, 'V' },
+       { "force-aiff-format"         , share__no_argument, 0, 0 },
+       { "force-raw-format"          , share__no_argument, 0, 0 },
+       { "lax"                       , share__no_argument, 0, 0 },
+       { "replay-gain"               , share__no_argument, 0, 0 },
+       { "ignore-chunk-sizes"        , share__no_argument, 0, 0 },
+       { "sector-align"              , share__no_argument, 0, 0 },
+       { "seekpoint"                 , share__required_argument, 0, 'S' },
+       { "padding"                   , share__required_argument, 0, 'P' },
+#if FLAC__HAS_OGG
+       { "ogg"                       , share__no_argument, 0, 0 },
+       { "serial-number"             , share__required_argument, 0, 0 },
+#endif
+       { "blocksize"                 , share__required_argument, 0, 'b' },
+       { "exhaustive-model-search"   , share__no_argument, 0, 'e' },
+       { "max-lpc-order"             , share__required_argument, 0, 'l' },
+       { "apodization"               , share__required_argument, 0, 'A' },
+       { "mid-side"                  , share__no_argument, 0, 'm' },
+       { "adaptive-mid-side"         , share__no_argument, 0, 'M' },
+       { "qlp-coeff-precision-search", share__no_argument, 0, 'p' },
+       { "qlp-coeff-precision"       , share__required_argument, 0, 'q' },
+       { "rice-partition-order"      , share__required_argument, 0, 'r' },
+       { "endian"                    , share__required_argument, 0, 0 },
+       { "channels"                  , share__required_argument, 0, 0 },
+       { "bps"                       , share__required_argument, 0, 0 },
+       { "sample-rate"               , share__required_argument, 0, 0 },
+       { "sign"                      , share__required_argument, 0, 0 },
+       { "input-size"                , share__required_argument, 0, 0 },
+
+       /*
+        * analysis options
+        */
+       { "residual-gnuplot", share__no_argument, 0, 0 },
+       { "residual-text", share__no_argument, 0, 0 },
+
+       /*
+        * negatives
+        */
+       { "no-decode-through-errors"  , share__no_argument, 0, 0 },
+       { "no-silent"                 , share__no_argument, 0, 0 },
+       { "no-force"                  , share__no_argument, 0, 0 },
+       { "no-seektable"              , share__no_argument, 0, 0 },
+       { "no-delete-input-file"      , share__no_argument, 0, 0 },
+       { "no-keep-foreign-metadata"  , share__no_argument, 0, 0 },
+       { "no-replay-gain"            , share__no_argument, 0, 0 },
+       { "no-ignore-chunk-sizes"     , share__no_argument, 0, 0 },
+       { "no-sector-align"           , share__no_argument, 0, 0 },
+       { "no-utf8-convert"           , share__no_argument, 0, 0 },
+       { "no-lax"                    , share__no_argument, 0, 0 },
+#if FLAC__HAS_OGG
+       { "no-ogg"                    , share__no_argument, 0, 0 },
+#endif
+       { "no-exhaustive-model-search", share__no_argument, 0, 0 },
+       { "no-mid-side"               , share__no_argument, 0, 0 },
+       { "no-adaptive-mid-side"      , share__no_argument, 0, 0 },
+       { "no-qlp-coeff-prec-search"  , share__no_argument, 0, 0 },
+       { "no-padding"                , share__no_argument, 0, 0 },
+       { "no-verify"                 , share__no_argument, 0, 0 },
+       { "no-warnings-as-errors"     , share__no_argument, 0, 0 },
+       { "no-residual-gnuplot"       , share__no_argument, 0, 0 },
+       { "no-residual-text"          , share__no_argument, 0, 0 },
+       /*
+        * undocumented debugging options for the test suite
+        */
+       { "disable-constant-subframes", share__no_argument, 0, 0 },
+       { "disable-fixed-subframes"   , share__no_argument, 0, 0 },
+       { "disable-verbatim-subframes", share__no_argument, 0, 0 },
+       { "no-md5-sum"                , share__no_argument, 0, 0 },
+
+       {0, 0, 0, 0}
+};
+
+
+/*
+ * global to hold command-line option values
+ */
+
+static struct {
+       FLAC__bool show_help;
+       FLAC__bool show_explain;
+       FLAC__bool show_version;
+       FLAC__bool mode_decode;
+       FLAC__bool verify;
+       FLAC__bool treat_warnings_as_errors;
+       FLAC__bool force_file_overwrite;
+       FLAC__bool continue_through_decode_errors;
+       replaygain_synthesis_spec_t replaygain_synthesis_spec;
+       FLAC__bool lax;
+       FLAC__bool test_only;
+       FLAC__bool analyze;
+       FLAC__bool use_ogg;
+       FLAC__bool has_serial_number; /* true iff --serial-number was used */
+       long serial_number; /* this is the Ogg serial number and is unused for native FLAC */
+       FLAC__bool force_to_stdout;
+       FLAC__bool force_aiff_format;
+       FLAC__bool force_raw_format;
+       FLAC__bool delete_input;
+       FLAC__bool keep_foreign_metadata;
+       FLAC__bool replay_gain;
+       FLAC__bool ignore_chunk_sizes;
+       FLAC__bool sector_align;
+       FLAC__bool utf8_convert; /* true by default, to convert tag strings from locale to utf-8, false if --no-utf8-convert used */
+       const char *cmdline_forced_outfilename;
+       const char *output_prefix;
+       analysis_options aopts;
+       int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */
+       size_t num_compression_settings;
+       compression_setting_t compression_settings[64]; /* bad MAGIC NUMBER but buffer overflow is checked */
+       const char *skip_specification;
+       const char *until_specification;
+       const char *cue_specification;
+       int format_is_big_endian;
+       int format_is_unsigned_samples;
+       int format_channels;
+       int format_bps;
+       int format_sample_rate;
+       off_t format_input_size;
+       char requested_seek_points[5000]; /* bad MAGIC NUMBER but buffer overflow is checked */
+       int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */
+       const char *cuesheet_filename;
+       FLAC__bool cued_seekpoints;
+       FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+
+       unsigned num_files;
+       char **filenames;
+
+       FLAC__StreamMetadata *vorbis_comment;
+       FLAC__StreamMetadata *pictures[64];
+       unsigned num_pictures;
+
+       struct {
+               FLAC__bool disable_constant_subframes;
+               FLAC__bool disable_fixed_subframes;
+               FLAC__bool disable_verbatim_subframes;
+               FLAC__bool do_md5;
+       } debug;
+} option_values;
+
+
+/*
+ * miscellaneous globals
+ */
+
+static FLAC__int32 align_reservoir_0[588], align_reservoir_1[588]; /* for carrying over samples from --sector-align */
+static FLAC__int32 *align_reservoir[2] = { align_reservoir_0, align_reservoir_1 };
+static unsigned align_reservoir_samples = 0; /* 0 .. 587 */
+
+
+int main(int argc, char *argv[])
+{
+       int retval = 0;
+
+#ifdef __EMX__
+       _response(&argc, &argv);
+       _wildcard(&argc, &argv);
+#endif
+
+       srand((unsigned)time(0));
+       setlocale(LC_ALL, "");
+       if(!init_options()) {
+               flac__utils_printf(stderr, 1, "ERROR: allocating memory\n");
+               retval = 1;
+       }
+       else {
+               if((retval = parse_options(argc, argv)) == 0)
+                       retval = do_it();
+       }
+
+       free_options();
+
+       return retval;
+}
+
+int do_it(void)
+{
+       int retval = 0;
+
+       if(option_values.show_version) {
+               show_version();
+               return 0;
+       }
+       else if(option_values.show_explain) {
+               show_explain();
+               return 0;
+       }
+       else if(option_values.show_help) {
+               show_help();
+               return 0;
+       }
+       else {
+               if(option_values.num_files == 0) {
+                       if(flac__utils_verbosity_ >= 1)
+                               short_usage();
+                       return 0;
+               }
+
+               /*
+                * tweak options; validate the values
+                */
+               if(!option_values.mode_decode) {
+                       if(0 != option_values.cue_specification)
+                               return usage_error("ERROR: --cue is not allowed in test mode\n");
+               }
+               else {
+                       if(option_values.test_only) {
+                               if(0 != option_values.skip_specification)
+                                       return usage_error("ERROR: --skip is not allowed in test mode\n");
+                               if(0 != option_values.until_specification)
+                                       return usage_error("ERROR: --until is not allowed in test mode\n");
+                               if(0 != option_values.cue_specification)
+                                       return usage_error("ERROR: --cue is not allowed in test mode\n");
+                               if(0 != option_values.analyze)
+                                       return usage_error("ERROR: analysis mode (-a/--analyze) and test mode (-t/--test) cannot be used together\n");
+                       }
+               }
+
+               if(0 != option_values.cue_specification && (0 != option_values.skip_specification || 0 != option_values.until_specification))
+                       return usage_error("ERROR: --cue may not be combined with --skip or --until\n");
+
+               if(option_values.format_channels >= 0) {
+                       if(option_values.format_channels == 0 || (unsigned)option_values.format_channels > FLAC__MAX_CHANNELS)
+                               return usage_error("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", option_values.format_channels, FLAC__MAX_CHANNELS);
+               }
+               if(option_values.format_bps >= 0) {
+                       if(option_values.format_bps != 8 && option_values.format_bps != 16 && option_values.format_bps != 24)
+                               return usage_error("ERROR: invalid bits per sample '%u' (must be 8/16/24)\n", option_values.format_bps);
+               }
+               if(option_values.format_sample_rate >= 0) {
+                       if(!FLAC__format_sample_rate_is_valid(option_values.format_sample_rate))
+                               return usage_error("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", option_values.format_sample_rate, FLAC__MAX_SAMPLE_RATE);
+               }
+               if(option_values.force_raw_format && option_values.force_aiff_format)
+                       return usage_error("ERROR: only one of --force-raw-format and --force-aiff-format allowed\n");
+               if(option_values.mode_decode) {
+                       if(!option_values.force_raw_format) {
+                               if(option_values.format_is_big_endian >= 0)
+                                       return usage_error("ERROR: --endian only allowed with --force-raw-format\n");
+                               if(option_values.format_is_unsigned_samples >= 0)
+                                       return usage_error("ERROR: --sign only allowed with --force-raw-format\n");
+                       }
+                       if(option_values.format_channels >= 0)
+                               return usage_error("ERROR: --channels not allowed with --decode\n");
+                       if(option_values.format_bps >= 0)
+                               return usage_error("ERROR: --bps not allowed with --decode\n");
+                       if(option_values.format_sample_rate >= 0)
+                               return usage_error("ERROR: --sample-rate not allowed with --decode\n");
+               }
+
+               if(option_values.ignore_chunk_sizes) {
+                       if(option_values.mode_decode)
+                               return usage_error("ERROR: --ignore-chunk-sizes only allowed for encoding\n");
+                       if(0 != option_values.sector_align)
+                               return usage_error("ERROR: --ignore-chunk-sizes not allowed with --sector-align\n");
+                       if(0 != option_values.until_specification)
+                               return usage_error("ERROR: --ignore-chunk-sizes not allowed with --until\n");
+                       if(0 != option_values.cue_specification)
+                               return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cue\n");
+                       if(0 != option_values.cuesheet_filename)
+                               return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cuesheet\n");
+               }
+               if(option_values.sector_align) {
+                       if(option_values.mode_decode)
+                               return usage_error("ERROR: --sector-align only allowed for encoding\n");
+                       if(0 != option_values.skip_specification)
+                               return usage_error("ERROR: --sector-align not allowed with --skip\n");
+                       if(0 != option_values.until_specification)
+                               return usage_error("ERROR: --sector-align not allowed with --until\n");
+                       if(0 != option_values.cue_specification)
+                               return usage_error("ERROR: --sector-align not allowed with --cue\n");
+                       if(option_values.format_channels >= 0 && option_values.format_channels != 2)
+                               return usage_error("ERROR: --sector-align can only be done with stereo input\n");
+                       if(option_values.format_bps >= 0 && option_values.format_bps != 16)
+                               return usage_error("ERROR: --sector-align can only be done with 16-bit samples\n");
+                       if(option_values.format_sample_rate >= 0 && option_values.format_sample_rate != 44100)
+                               return usage_error("ERROR: --sector-align can only be done with a sample rate of 44100\n");
+               }
+               if(option_values.replay_gain) {
+                       if(option_values.force_to_stdout)
+                               return usage_error("ERROR: --replay-gain not allowed with -c/--stdout\n");
+                       if(option_values.mode_decode)
+                               return usage_error("ERROR: --replay-gain only allowed for encoding\n");
+                       if(option_values.format_channels > 2)
+                               return usage_error("ERROR: --replay-gain can only be done with mono/stereo input\n");
+                       if(option_values.format_sample_rate >= 0 && !grabbag__replaygain_is_valid_sample_frequency(option_values.format_sample_rate))
+                               return usage_error("ERROR: invalid sample rate used with --replay-gain\n");
+                       /*
+                        * We want to reserve padding space for the ReplayGain
+                        * tags that we will set later, to avoid rewriting the
+                        * whole file.
+                        */
+                       if(
+                               (option_values.padding >= 0 && option_values.padding < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) ||
+                               (option_values.padding < 0 && FLAC_ENCODE__DEFAULT_PADDING < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED)
+                       ) {
+                               flac__utils_printf(stderr, 1, "NOTE: --replay-gain may leave a small PADDING block even with --no-padding\n");
+                               option_values.padding = GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+                       }
+                       else {
+                               option_values.padding += GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+                       }
+               }
+               if(option_values.num_files > 1 && option_values.cmdline_forced_outfilename) {
+                       return usage_error("ERROR: -o/--output-name cannot be used with multiple files\n");
+               }
+               if(option_values.cmdline_forced_outfilename && option_values.output_prefix) {
+                       return usage_error("ERROR: --output-prefix conflicts with -o/--output-name\n");
+               }
+               if(!option_values.mode_decode && 0 != option_values.cuesheet_filename && option_values.num_files > 1) {
+                       return usage_error("ERROR: --cuesheet cannot be used when encoding multiple files\n");
+               }
+               if(option_values.keep_foreign_metadata) {
+                       /* we're not going to try and support the re-creation of broken WAVE files */
+                       if(option_values.ignore_chunk_sizes)
+                               return usage_error("ERROR: using --keep-foreign-metadata cannot be used with --ignore-chunk-sizes\n");
+                       if(option_values.test_only)
+                               return usage_error("ERROR: --keep-foreign-metadata is not allowed in test mode\n");
+                       if(option_values.analyze)
+                               return usage_error("ERROR: --keep-foreign-metadata is not allowed in analyis mode\n");
+                       /*@@@@@@*/
+                       if(option_values.delete_input)
+                               return usage_error("ERROR: using --delete-input-file with --keep-foreign-metadata has been disabled until more testing has been done.\n");
+                       flac__utils_printf(stderr, 1, "NOTE: --keep-foreign-metadata is a new feature; make sure to test the output file before deleting the original.\n");
+               }
+       }
+
+       flac__utils_printf(stderr, 2, "\n");
+       flac__utils_printf(stderr, 2, "flac %s, Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson\n", FLAC__VERSION_STRING);
+       flac__utils_printf(stderr, 2, "flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are\n");
+       flac__utils_printf(stderr, 2, "welcome to redistribute it under certain conditions.  Type `flac' for details.\n\n");
+
+       if(option_values.mode_decode) {
+               FLAC__bool first = true;
+
+               if(option_values.num_files == 0) {
+                       retval = decode_file("-");
+               }
+               else {
+                       unsigned i;
+                       if(option_values.num_files > 1)
+                               option_values.cmdline_forced_outfilename = 0;
+                       for(i = 0, retval = 0; i < option_values.num_files; i++) {
+                               if(0 == strcmp(option_values.filenames[i], "-") && !first)
+                                       continue;
+                               retval |= decode_file(option_values.filenames[i]);
+                               first = false;
+                       }
+               }
+       }
+       else { /* encode */
+               FLAC__bool first = true;
+
+               if(option_values.ignore_chunk_sizes)
+                       flac__utils_printf(stderr, 1, "INFO: Make sure you know what you're doing when using --ignore-chunk-sizes.\n      Improper use can cause flac to encode non-audio data as audio.\n");
+
+               if(option_values.num_files == 0) {
+                       retval = encode_file("-", first, true);
+               }
+               else {
+                       unsigned i;
+                       if(option_values.num_files > 1)
+                               option_values.cmdline_forced_outfilename = 0;
+                       for(i = 0, retval = 0; i < option_values.num_files; i++) {
+                               if(0 == strcmp(option_values.filenames[i], "-") && !first)
+                                       continue;
+                               retval |= encode_file(option_values.filenames[i], first, i == (option_values.num_files-1));
+                               first = false;
+                       }
+                       if(option_values.replay_gain && retval == 0) {
+                               float album_gain, album_peak;
+                               grabbag__replaygain_get_album(&album_gain, &album_peak);
+                               for(i = 0; i < option_values.num_files; i++) {
+                                       const char *error, *outfilename = get_encoded_outfilename(option_values.filenames[i]);
+                                       if(0 == outfilename) {
+                                               flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", option_values.filenames[i]);
+                                               return 1;
+                                       }
+                                       if(0 == strcmp(option_values.filenames[i], "-")) {
+                                               FLAC__ASSERT(0);
+                                               /* double protection */
+                                               flac__utils_printf(stderr, 1, "internal error\n");
+                                               return 2;
+                                       }
+                                       if(0 != (error = grabbag__replaygain_store_to_file_album(outfilename, album_gain, album_peak, /*preserve_modtime=*/true))) {
+                                               flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain album tags (%s)\n", outfilename, error);
+                                               retval = 1;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return retval;
+}
+
+FLAC__bool init_options(void)
+{
+       option_values.show_help = false;
+       option_values.show_explain = false;
+       option_values.mode_decode = false;
+       option_values.verify = false;
+       option_values.treat_warnings_as_errors = false;
+       option_values.force_file_overwrite = false;
+       option_values.continue_through_decode_errors = false;
+       option_values.replaygain_synthesis_spec.apply = false;
+       option_values.replaygain_synthesis_spec.use_album_gain = true;
+       option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD;
+       option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_LOW;
+       option_values.replaygain_synthesis_spec.preamp = 0.0;
+       option_values.lax = false;
+       option_values.test_only = false;
+       option_values.analyze = false;
+       option_values.use_ogg = false;
+       option_values.has_serial_number = false;
+       option_values.serial_number = 0;
+       option_values.force_to_stdout = false;
+       option_values.force_aiff_format = false;
+       option_values.force_raw_format = false;
+       option_values.delete_input = false;
+       option_values.keep_foreign_metadata = false;
+       option_values.replay_gain = false;
+       option_values.ignore_chunk_sizes = false;
+       option_values.sector_align = false;
+       option_values.utf8_convert = true;
+       option_values.cmdline_forced_outfilename = 0;
+       option_values.output_prefix = 0;
+       option_values.aopts.do_residual_text = false;
+       option_values.aopts.do_residual_gnuplot = false;
+       option_values.padding = -1;
+       option_values.num_compression_settings = 1;
+       option_values.compression_settings[0].type = CST_COMPRESSION_LEVEL;
+       option_values.compression_settings[0].value.t_unsigned = 5;
+       option_values.skip_specification = 0;
+       option_values.until_specification = 0;
+       option_values.cue_specification = 0;
+       option_values.format_is_big_endian = -1;
+       option_values.format_is_unsigned_samples = -1;
+       option_values.format_channels = -1;
+       option_values.format_bps = -1;
+       option_values.format_sample_rate = -1;
+       option_values.format_input_size = (off_t)(-1);
+       option_values.requested_seek_points[0] = '\0';
+       option_values.num_requested_seek_points = -1;
+       option_values.cuesheet_filename = 0;
+       option_values.cued_seekpoints = true;
+       option_values.channel_map_none = false;
+
+       option_values.num_files = 0;
+       option_values.filenames = 0;
+
+       if(0 == (option_values.vorbis_comment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
+               return false;
+       option_values.num_pictures = 0;
+
+       option_values.debug.disable_constant_subframes = false;
+       option_values.debug.disable_fixed_subframes = false;
+       option_values.debug.disable_verbatim_subframes = false;
+       option_values.debug.do_md5 = true;
+
+       return true;
+}
+
+int parse_options(int argc, char *argv[])
+{
+       int short_option;
+       int option_index = 1;
+       FLAC__bool had_error = false;
+       const char *short_opts = "0123456789aA:b:cdefFhHl:mMo:pP:q:r:sS:tT:vVw";
+
+       while ((short_option = share__getopt_long(argc, argv, short_opts, long_options_, &option_index)) != -1) {
+               switch (short_option) {
+                       case 0: /* long option with no equivalent short option */
+                               had_error |= (parse_option(short_option, long_options_[option_index].name, share__optarg) != 0);
+                               break;
+                       case '?':
+                       case ':':
+                               had_error = true;
+                               break;
+                       default: /* short option */
+                               had_error |= (parse_option(short_option, 0, share__optarg) != 0);
+                               break;
+               }
+       }
+
+       if(had_error) {
+               return 1;
+       }
+
+       FLAC__ASSERT(share__optind <= argc);
+
+       option_values.num_files = argc - share__optind;
+
+       if(option_values.num_files > 0) {
+               unsigned i = 0;
+               if(0 == (option_values.filenames = (char**)malloc(sizeof(char*) * option_values.num_files)))
+                       die("out of memory allocating space for file names list");
+               while(share__optind < argc)
+                       option_values.filenames[i++] = local_strdup(argv[share__optind++]);
+       }
+
+       return 0;
+}
+
+int parse_option(int short_option, const char *long_option, const char *option_argument)
+{
+       const char *violation;
+       char *p;
+       int i;
+
+       if(short_option == 0) {
+               FLAC__ASSERT(0 != long_option);
+               if(0 == strcmp(long_option, "totally-silent")) {
+                       flac__utils_verbosity_ = 0;
+               }
+               else if(0 == strcmp(long_option, "delete-input-file")) {
+                       option_values.delete_input = true;
+               }
+               else if(0 == strcmp(long_option, "keep-foreign-metadata")) {
+                       option_values.keep_foreign_metadata = true;
+               }
+               else if(0 == strcmp(long_option, "output-prefix")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.output_prefix = option_argument;
+               }
+               else if(0 == strcmp(long_option, "skip")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.skip_specification = option_argument;
+               }
+               else if(0 == strcmp(long_option, "until")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.until_specification = option_argument;
+               }
+               else if(0 == strcmp(long_option, "input-size")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       {
+                               char *end;
+#ifdef _MSC_VER
+                               FLAC__int64 i;
+                               i = local__strtoll(option_argument, &end);
+#else
+                               long long i;
+                               i = strtoll(option_argument, &end, 10);
+#endif
+                               if(0 == strlen(option_argument) || *end)
+                                       return usage_error("ERROR: --%s must be a number\n", long_option);
+                               option_values.format_input_size = (off_t)i;
+                               if(option_values.format_input_size != i) /* check if off_t is smaller than long long */
+                                       return usage_error("ERROR: --%s too large; this build of flac does not support filesizes over 2GB\n", long_option);
+                               if(option_values.format_input_size <= 0)
+                                       return usage_error("ERROR: --%s must be > 0\n", long_option);
+                       }
+               }
+               else if(0 == strcmp(long_option, "cue")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.cue_specification = option_argument;
+               }
+               else if(0 == strcmp(long_option, "apply-replaygain-which-is-not-lossless")) {
+                       option_values.replaygain_synthesis_spec.apply = true;
+                       if (0 != option_argument) {
+                               char *p;
+                               option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__NONE;
+                               option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_NONE;
+                               option_values.replaygain_synthesis_spec.preamp = strtod(option_argument, &p);
+                               for ( ; *p; p++) {
+                                       if (*p == 'a')
+                                               option_values.replaygain_synthesis_spec.use_album_gain = true;
+                                       else if (*p == 't')
+                                               option_values.replaygain_synthesis_spec.use_album_gain = false;
+                                       else if (*p == 'l')
+                                               option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__PEAK;
+                                       else if (*p == 'L')
+                                               option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD;
+                                       else if (*p == 'n' && p[1] >= '0' && p[1] <= '3') {
+                                               option_values.replaygain_synthesis_spec.noise_shaping = p[1] - '0';
+                                               p++;
+                                       }
+                                       else
+                                               return usage_error("ERROR: bad specification string \"%s\" for --%s\n", option_argument, long_option);
+                               }
+                       }
+               }
+               else if(0 == strcmp(long_option, "channel-map")) {
+                       if (0 == option_argument || strcmp(option_argument, "none"))
+                               return usage_error("ERROR: only --channel-map=none currently supported\n");
+                       option_values.channel_map_none = true;
+               }
+               else if(0 == strcmp(long_option, "cuesheet")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.cuesheet_filename = option_argument;
+               }
+               else if(0 == strcmp(long_option, "picture")) {
+                       const unsigned max_pictures = sizeof(option_values.pictures)/sizeof(option_values.pictures[0]);
+                       FLAC__ASSERT(0 != option_argument);
+                       if(option_values.num_pictures >= max_pictures)
+                               return usage_error("ERROR: too many --picture arguments, only %u allowed\n", max_pictures);
+                       if(0 == (option_values.pictures[option_values.num_pictures] = grabbag__picture_parse_specification(option_argument, &violation)))
+                               return usage_error("ERROR: (--picture) %s\n", violation);
+                       option_values.num_pictures++;
+               }
+               else if(0 == strcmp(long_option, "tag-from-file")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/true, /*raw=*/!option_values.utf8_convert, &violation))
+                               return usage_error("ERROR: (--tag-from-file) %s\n", violation);
+               }
+               else if(0 == strcmp(long_option, "no-cued-seekpoints")) {
+                       option_values.cued_seekpoints = false;
+               }
+               else if(0 == strcmp(long_option, "force-aiff-format")) {
+                       option_values.force_aiff_format = true;
+               }
+               else if(0 == strcmp(long_option, "force-raw-format")) {
+                       option_values.force_raw_format = true;
+               }
+               else if(0 == strcmp(long_option, "lax")) {
+                       option_values.lax = true;
+               }
+               else if(0 == strcmp(long_option, "replay-gain")) {
+                       option_values.replay_gain = true;
+               }
+               else if(0 == strcmp(long_option, "ignore-chunk-sizes")) {
+                       option_values.ignore_chunk_sizes = true;
+               }
+               else if(0 == strcmp(long_option, "sector-align")) {
+                       option_values.sector_align = true;
+               }
+#if FLAC__HAS_OGG
+               else if(0 == strcmp(long_option, "ogg")) {
+                       option_values.use_ogg = true;
+               }
+               else if(0 == strcmp(long_option, "serial-number")) {
+                       option_values.has_serial_number = true;
+                       option_values.serial_number = atol(option_argument);
+               }
+#endif
+               else if(0 == strcmp(long_option, "endian")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       if(0 == strncmp(option_argument, "big", strlen(option_argument)))
+                               option_values.format_is_big_endian = true;
+                       else if(0 == strncmp(option_argument, "little", strlen(option_argument)))
+                               option_values.format_is_big_endian = false;
+                       else
+                               return usage_error("ERROR: argument to --endian must be \"big\" or \"little\"\n");
+               }
+               else if(0 == strcmp(long_option, "channels")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.format_channels = atoi(option_argument);
+               }
+               else if(0 == strcmp(long_option, "bps")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.format_bps = atoi(option_argument);
+               }
+               else if(0 == strcmp(long_option, "sample-rate")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       option_values.format_sample_rate = atoi(option_argument);
+               }
+               else if(0 == strcmp(long_option, "sign")) {
+                       FLAC__ASSERT(0 != option_argument);
+                       if(0 == strncmp(option_argument, "signed", strlen(option_argument)))
+                               option_values.format_is_unsigned_samples = false;
+                       else if(0 == strncmp(option_argument, "unsigned", strlen(option_argument)))
+                               option_values.format_is_unsigned_samples = true;
+                       else
+                               return usage_error("ERROR: argument to --sign must be \"signed\" or \"unsigned\"\n");
+               }
+               else if(0 == strcmp(long_option, "residual-gnuplot")) {
+                       option_values.aopts.do_residual_gnuplot = true;
+               }
+               else if(0 == strcmp(long_option, "residual-text")) {
+                       option_values.aopts.do_residual_text = true;
+               }
+               /*
+                * negatives
+                */
+               else if(0 == strcmp(long_option, "no-decode-through-errors")) {
+                       option_values.continue_through_decode_errors = false;
+               }
+               else if(0 == strcmp(long_option, "no-silent")) {
+                       flac__utils_verbosity_ = 2;
+               }
+               else if(0 == strcmp(long_option, "no-force")) {
+                       option_values.force_file_overwrite = false;
+               }
+               else if(0 == strcmp(long_option, "no-seektable")) {
+                       option_values.num_requested_seek_points = 0;
+                       option_values.requested_seek_points[0] = '\0';
+               }
+               else if(0 == strcmp(long_option, "no-delete-input-file")) {
+                       option_values.delete_input = false;
+               }
+               else if(0 == strcmp(long_option, "no-keep-foreign-metadata")) {
+                       option_values.keep_foreign_metadata = false;
+               }
+               else if(0 == strcmp(long_option, "no-replay-gain")) {
+                       option_values.replay_gain = false;
+               }
+               else if(0 == strcmp(long_option, "no-ignore-chunk-sizes")) {
+                       option_values.ignore_chunk_sizes = false;
+               }
+               else if(0 == strcmp(long_option, "no-sector-align")) {
+                       option_values.sector_align = false;
+               }
+               else if(0 == strcmp(long_option, "no-utf8-convert")) {
+                       option_values.utf8_convert = false;
+               }
+               else if(0 == strcmp(long_option, "no-lax")) {
+                       option_values.lax = false;
+               }
+#if FLAC__HAS_OGG
+               else if(0 == strcmp(long_option, "no-ogg")) {
+                       option_values.use_ogg = false;
+               }
+#endif
+               else if(0 == strcmp(long_option, "no-exhaustive-model-search")) {
+                       add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, false);
+               }
+               else if(0 == strcmp(long_option, "no-mid-side")) {
+                       add_compression_setting_bool(CST_DO_MID_SIDE, false);
+                       add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+               }
+               else if(0 == strcmp(long_option, "no-adaptive-mid-side")) {
+                       add_compression_setting_bool(CST_DO_MID_SIDE, false);
+                       add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+               }
+               else if(0 == strcmp(long_option, "no-qlp-coeff-prec-search")) {
+                       add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, false);
+               }
+               else if(0 == strcmp(long_option, "no-padding")) {
+                       option_values.padding = 0;
+               }
+               else if(0 == strcmp(long_option, "no-verify")) {
+                       option_values.verify = false;
+               }
+               else if(0 == strcmp(long_option, "no-warnings-as-errors")) {
+                       option_values.treat_warnings_as_errors = false;
+               }
+               else if(0 == strcmp(long_option, "no-residual-gnuplot")) {
+                       option_values.aopts.do_residual_gnuplot = false;
+               }
+               else if(0 == strcmp(long_option, "no-residual-text")) {
+                       option_values.aopts.do_residual_text = false;
+               }
+               else if(0 == strcmp(long_option, "disable-constant-subframes")) {
+                       option_values.debug.disable_constant_subframes = true;
+               }
+               else if(0 == strcmp(long_option, "disable-fixed-subframes")) {
+                       option_values.debug.disable_fixed_subframes = true;
+               }
+               else if(0 == strcmp(long_option, "disable-verbatim-subframes")) {
+                       option_values.debug.disable_verbatim_subframes = true;
+               }
+               else if(0 == strcmp(long_option, "no-md5-sum")) {
+                       option_values.debug.do_md5 = false;
+               }
+       }
+       else {
+               switch(short_option) {
+                       case 'h':
+                               option_values.show_help = true;
+                               break;
+                       case 'H':
+                               option_values.show_explain = true;
+                               break;
+                       case 'v':
+                               option_values.show_version = true;
+                               break;
+                       case 'd':
+                               option_values.mode_decode = true;
+                               break;
+                       case 'a':
+                               option_values.mode_decode = true;
+                               option_values.analyze = true;
+                               break;
+                       case 't':
+                               option_values.mode_decode = true;
+                               option_values.test_only = true;
+                               break;
+                       case 'c':
+                               option_values.force_to_stdout = true;
+                               break;
+                       case 's':
+                               flac__utils_verbosity_ = 1;
+                               break;
+                       case 'f':
+                               option_values.force_file_overwrite = true;
+                               break;
+                       case 'o':
+                               FLAC__ASSERT(0 != option_argument);
+                               option_values.cmdline_forced_outfilename = option_argument;
+                               break;
+                       case 'F':
+                               option_values.continue_through_decode_errors = true;
+                               break;
+                       case 'T':
+                               FLAC__ASSERT(0 != option_argument);
+                               if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/false, /*raw=*/!option_values.utf8_convert, &violation))
+                                       return usage_error("ERROR: (-T/--tag) %s\n", violation);
+                               break;
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                               add_compression_setting_unsigned(CST_COMPRESSION_LEVEL, short_option-'0');
+                               break;
+                       case '9':
+                               return usage_error("ERROR: compression level '9' is reserved\n");
+                       case 'V':
+                               option_values.verify = true;
+                               break;
+                       case 'w':
+                               option_values.treat_warnings_as_errors = true;
+                               break;
+                       case 'S':
+                               FLAC__ASSERT(0 != option_argument);
+                               if(0 == strcmp(option_argument, "-")) {
+                                       option_values.num_requested_seek_points = 0;
+                                       option_values.requested_seek_points[0] = '\0';
+                               }
+                               else {
+                                       if(option_values.num_requested_seek_points < 0)
+                                               option_values.num_requested_seek_points = 0;
+                                       option_values.num_requested_seek_points++;
+                                       if(strlen(option_values.requested_seek_points)+strlen(option_argument)+2 >= sizeof(option_values.requested_seek_points)) {
+                                               return usage_error("ERROR: too many seekpoints requested\n");
+                                       }
+                                       else {
+                                               strcat(option_values.requested_seek_points, option_argument);
+                                               strcat(option_values.requested_seek_points, ";");
+                                       }
+                               }
+                               break;
+                       case 'P':
+                               FLAC__ASSERT(0 != option_argument);
+                               option_values.padding = atoi(option_argument);
+                               if(option_values.padding < 0)
+                                       return usage_error("ERROR: argument to -%c must be >= 0; for no padding use -%c-\n", short_option, short_option);
+                               break;
+                       case 'b':
+                               FLAC__ASSERT(0 != option_argument);
+                               i = atoi(option_argument);
+                               if((i < (int)FLAC__MIN_BLOCK_SIZE || i > (int)FLAC__MAX_BLOCK_SIZE))
+                                       return usage_error("ERROR: invalid blocksize (-%c) '%d', must be >= %u and <= %u\n", short_option, i, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+                               add_compression_setting_unsigned(CST_BLOCKSIZE, (unsigned)i);
+                               break;
+                       case 'e':
+                               add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, true);
+                               break;
+                       case 'E':
+                               add_compression_setting_bool(CST_DO_ESCAPE_CODING, true);
+                               break;
+                       case 'l':
+                               FLAC__ASSERT(0 != option_argument);
+                               i = atoi(option_argument);
+                               if((i < 0 || i > (int)FLAC__MAX_LPC_ORDER))
+                                       return usage_error("ERROR: invalid LPC order (-%c) '%d', must be >= %u and <= %u\n", short_option, i, 0, FLAC__MAX_LPC_ORDER);
+                               add_compression_setting_unsigned(CST_MAX_LPC_ORDER, (unsigned)i);
+                               break;
+                       case 'A':
+                               FLAC__ASSERT(0 != option_argument);
+                               add_compression_setting_string(CST_APODIZATION, option_argument);
+                               break;
+                       case 'm':
+                               add_compression_setting_bool(CST_DO_MID_SIDE, true);
+                               add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
+                               break;
+                       case 'M':
+                               add_compression_setting_bool(CST_DO_MID_SIDE, true);
+                               add_compression_setting_bool(CST_LOOSE_MID_SIDE, true);
+                               break;
+                       case 'p':
+                               add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, true);
+                               break;
+                       case 'q':
+                               FLAC__ASSERT(0 != option_argument);
+                               i = atoi(option_argument);
+                               if(i < 0 || (i > 0 && (i < (int)FLAC__MIN_QLP_COEFF_PRECISION || i > (int)FLAC__MAX_QLP_COEFF_PRECISION)))
+                                       return usage_error("ERROR: invalid value '%d' for qlp coeff precision (-%c), must be 0 or between %u and %u, inclusive\n", i, short_option, FLAC__MIN_QLP_COEFF_PRECISION, FLAC__MAX_QLP_COEFF_PRECISION);
+                               add_compression_setting_unsigned(CST_QLP_COEFF_PRECISION, (unsigned)i);
+                               break;
+                       case 'r':
+                               FLAC__ASSERT(0 != option_argument);
+                               p = strchr(option_argument, ',');
+                               if(0 == p) {
+                                       add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, 0);
+                                       i = atoi(option_argument);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i);
+                               }
+                               else {
+                                       i = atoi(option_argument);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for min residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, (unsigned)i);
+                                       i = atoi(++p);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for max residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i);
+                               }
+                               break;
+                       case 'R':
+                               i = atoi(option_argument);
+                               if(i < 0)
+                                       return usage_error("ERROR: invalid value '%d' for Rice parameter search distance (-%c), must be >= 0\n", i, short_option);
+                               add_compression_setting_unsigned(CST_RICE_PARAMETER_SEARCH_DIST, (unsigned)i);
+                               break;
+                       default:
+                               FLAC__ASSERT(0);
+               }
+       }
+
+       return 0;
+}
+
+void free_options(void)
+{
+       unsigned i;
+       if(0 != option_values.filenames) {
+               for(i = 0; i < option_values.num_files; i++) {
+                       if(0 != option_values.filenames[i])
+                               free(option_values.filenames[i]);
+               }
+               free(option_values.filenames);
+       }
+       if(0 != option_values.vorbis_comment)
+               FLAC__metadata_object_delete(option_values.vorbis_comment);
+       for(i = 0; i < option_values.num_pictures; i++)
+               FLAC__metadata_object_delete(option_values.pictures[i]);
+}
+
+void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_bool = value;
+       option_values.num_compression_settings++;
+}
+
+void add_compression_setting_string(compression_setting_type_t type, const char *value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_string = value;
+       option_values.num_compression_settings++;
+}
+
+void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_unsigned = value;
+       option_values.num_compression_settings++;
+}
+
+int usage_error(const char *message, ...)
+{
+       if(flac__utils_verbosity_ >= 1) {
+               va_list args;
+
+               FLAC__ASSERT(0 != message);
+
+               va_start(args, message);
+
+               (void) vfprintf(stderr, message, args);
+
+               va_end(args);
+
+               printf("Type \"flac\" for a usage summary or \"flac --help\" for all options\n");
+       }
+
+       return 1;
+}
+
+void show_version(void)
+{
+       printf("flac %s\n", FLAC__VERSION_STRING);
+}
+
+static void usage_header(void)
+{
+       printf("===============================================================================\n");
+       printf("flac - Command-line FLAC encoder/decoder version %s\n", FLAC__VERSION_STRING);
+       printf("Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson\n");
+       printf("\n");
+       printf("This program is free software; you can redistribute it and/or\n");
+       printf("modify it under the terms of the GNU General Public License\n");
+       printf("as published by the Free Software Foundation; either version 2\n");
+       printf("of the License, or (at your option) any later version.\n");
+       printf("\n");
+       printf("This program is distributed in the hope that it will be useful,\n");
+       printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+       printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
+       printf("GNU General Public License for more details.\n");
+       printf("\n");
+       printf("You should have received a copy of the GNU General Public License\n");
+       printf("along with this program; if not, write to the Free Software\n");
+       printf("Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n");
+       printf("===============================================================================\n");
+}
+
+static void usage_summary(void)
+{
+       printf("Usage:\n");
+       printf("\n");
+       printf(" Encoding: flac [<general-options>] [<encoding/format-options>] [INPUTFILE [...]]\n");
+       printf(" Decoding: flac -d [<general-options>] [<format-options>] [FLACFILE [...]]\n");
+       printf("  Testing: flac -t [<general-options>] [FLACFILE [...]]\n");
+       printf("Analyzing: flac -a [<general-options>] [<analysis-options>] [FLACFILE [...]]\n");
+       printf("\n");
+}
+
+void short_usage(void)
+{
+       usage_header();
+       printf("\n");
+       printf("This is the short help; for all options use 'flac --help'; for even more\n");
+       printf("instructions use 'flac --explain'\n");
+       printf("\n");
+       printf("To encode:\n");
+       printf("  flac [-#] [INPUTFILE [...]]\n");
+       printf("\n");
+       printf("  -# is -0 (fastest compression) to -8 (highest compression); -5 is the default\n");
+       printf("\n");
+       printf("To decode:\n");
+       printf("  flac -d [INPUTFILE [...]]\n");
+       printf("\n");
+       printf("To test:\n");
+       printf("  flac -t [INPUTFILE [...]]\n");
+}
+
+void show_help(void)
+{
+       usage_header();
+       usage_summary();
+       printf("general options:\n");
+       printf("  -v, --version                Show the flac version number\n");
+       printf("  -h, --help                   Show this screen\n");
+       printf("  -H, --explain                Show detailed explanation of usage and options\n");
+       printf("  -d, --decode                 Decode (the default behavior is to encode)\n");
+       printf("  -t, --test                   Same as -d except no decoded file is written\n");
+       printf("  -a, --analyze                Same as -d except an analysis file is written\n");
+       printf("  -c, --stdout                 Write output to stdout\n");
+       printf("  -s, --silent                 Do not write runtime encode/decode statistics\n");
+       printf("      --totally-silent         Do not print anything, including errors\n");
+       printf("      --no-utf8-convert        Do not convert tags from local charset to UTF-8\n");
+       printf("  -w, --warnings-as-errors     Treat all warnings as errors\n");
+       printf("  -f, --force                  Force overwriting of output files\n");
+       printf("  -o, --output-name=FILENAME   Force the output file name\n");
+       printf("      --output-prefix=STRING   Prepend STRING to output names\n");
+       printf("      --delete-input-file      Deletes after a successful encode/decode\n");
+       printf("      --keep-foreign-metadata  Save/restore WAVE or AIFF non-audio chunks\n");
+       printf("      --skip={#|mm:ss.ss}      Skip the given initial samples for each input\n");
+       printf("      --until={#|[+|-]mm:ss.ss}  Stop at the given sample for each input file\n");
+#if FLAC__HAS_OGG
+       printf("      --ogg                    Use Ogg as transport layer\n");
+       printf("      --serial-number          Serial number to use for the FLAC stream\n");
+#endif
+       printf("analysis options:\n");
+       printf("      --residual-text          Include residual signal in text output\n");
+       printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
+       printf("decoding options:\n");
+       printf("  -F, --decode-through-errors  Continue decoding through stream errors\n");
+       printf("      --cue=[#.#][-[#.#]]      Set the beginning and ending cuepoints to decode\n");
+       printf("encoding options:\n");
+       printf("  -V, --verify                 Verify a correct encoding\n");
+       printf("      --lax                    Allow encoder to generate non-Subset files\n");
+#if 0 /*@@@ currently undocumented */
+       printf("      --ignore-chunk-sizes     Ignore data chunk sizes in WAVE/AIFF files\n");
+#endif
+       printf("      --sector-align           Align multiple files on sector boundaries\n");
+       printf("      --replay-gain            Calculate ReplayGain & store in FLAC tags\n");
+       printf("      --cuesheet=FILENAME      Import cuesheet and store in CUESHEET block\n");
+       printf("      --picture=SPECIFICATION  Import picture and store in PICTURE block\n");
+       printf("  -T, --tag=FIELD=VALUE        Add a FLAC tag; may appear multiple times\n");
+       printf("      --tag-from-file=FIELD=FILENAME   Like --tag but gets value from file\n");
+       printf("  -S, --seekpoint={#|X|#x|#s}  Add seek point(s)\n");
+       printf("  -P, --padding=#              Write a PADDING block of length #\n");
+       printf("  -0, --compression-level-0, --fast  Synonymous with -l 0 -b 1152 -r 3\n");
+       printf("  -1, --compression-level-1          Synonymous with -l 0 -b 1152 -M -r 3\n");
+       printf("  -2, --compression-level-2          Synonymous with -l 0 -b 1152 -m -r 3\n");
+       printf("  -3, --compression-level-3          Synonymous with -l 6 -b 4096 -r 4\n");
+       printf("  -4, --compression-level-4          Synonymous with -l 8 -b 4096 -M -r 4\n");
+       printf("  -5, --compression-level-5          Synonymous with -l 8 -b 4096 -m -r 5\n");
+       printf("  -6, --compression-level-6          Synonymous with -l 8 -b 4096 -m -r 6\n");
+       printf("  -7, --compression-level-7          Synonymous with -l 8 -b 4096 -m -e -r 6\n");
+       printf("  -8, --compression-level-8, --best  Synonymous with -l 12 -b 4096 -m -e -r 6\n");
+       printf("  -b, --blocksize=#                  Specify blocksize in samples\n");
+       printf("  -m, --mid-side                     Try mid-side coding for each frame\n");
+       printf("  -M, --adaptive-mid-side            Adaptive mid-side coding for all frames\n");
+       printf("  -e, --exhaustive-model-search      Do exhaustive model search (expensive!)\n");
+       printf("  -A, --apodization=\"function\"       Window audio data with given the function\n");
+       printf("  -l, --max-lpc-order=#              Max LPC order; 0 => only fixed predictors\n");
+       printf("  -p, --qlp-coeff-precision-search   Exhaustively search LP coeff quantization\n");
+       printf("  -q, --qlp-coeff-precision=#        Specify precision in bits\n");
+       printf("  -r, --rice-partition-order=[#,]#   Set [min,]max residual partition order\n");
+       printf("format options:\n");
+       printf("      --endian={big|little}    Set byte order for samples\n");
+       printf("      --channels=#             Number of channels\n");
+       printf("      --bps=#                  Number of bits per sample\n");
+       printf("      --sample-rate=#          Sample rate in Hz\n");
+       printf("      --sign={signed|unsigned} Sign of samples\n");
+       printf("      --input-size=#           Size of the raw input in bytes\n");
+       printf("      --force-aiff-format      Force decoding to AIFF format\n");
+       printf("      --force-raw-format       Treat input or output as raw samples\n");
+       printf("negative options:\n");
+       printf("      --no-adaptive-mid-side\n");
+       printf("      --no-decode-through-errors\n");
+       printf("      --no-delete-input-file\n");
+       printf("      --no-keep-foreign-metadata\n");
+       printf("      --no-exhaustive-model-search\n");
+       printf("      --no-lax\n");
+       printf("      --no-mid-side\n");
+#if FLAC__HAS_OGG
+       printf("      --no-ogg\n");
+#endif
+       printf("      --no-padding\n");
+       printf("      --no-qlp-coeff-prec-search\n");
+       printf("      --no-replay-gain\n");
+       printf("      --no-residual-gnuplot\n");
+       printf("      --no-residual-text\n");
+#if 0 /*@@@ currently undocumented */
+       printf("      --no-ignore-chunk-sizes\n");
+#endif
+       printf("      --no-sector-align\n");
+       printf("      --no-seektable\n");
+       printf("      --no-silent\n");
+       printf("      --no-force\n");
+       printf("      --no-verify\n");
+       printf("      --no-warnings-as-errors\n");
+}
+
+void show_explain(void)
+{
+       usage_header();
+       usage_summary();
+       printf("For encoding:\n");
+       printf("  The input file(s) may be a PCM WAVE file, AIFF (or uncompressed AIFF-C)\n");
+       printf("  file, or raw samples.\n");
+       printf("  The output file(s) will be in native FLAC or Ogg FLAC format\n");
+       printf("For decoding, the reverse is true.\n");
+       printf("\n");
+       printf("A single INPUTFILE may be - for stdin.  No INPUTFILE implies stdin.  Use of\n");
+       printf("stdin implies -c (write to stdout).  Normally you should use:\n");
+       printf("   flac [options] -o outfilename  or  flac -d [options] -o outfilename\n");
+       printf("instead of:\n");
+       printf("   flac [options] > outfilename   or  flac -d [options] > outfilename\n");
+       printf("since the former allows flac to seek backwards to write the STREAMINFO or\n");
+       printf("WAVE/AIFF header contents when necessary.\n");
+       printf("\n");
+       printf("flac checks for the presence of a AIFF/WAVE header to decide whether or not to\n");
+       printf("treat an input file as AIFF/WAVE format or raw samples.  If any input file is\n");
+       printf("raw you must specify the format options {-fb|fl} -fc -fp and -fs, which will\n");
+       printf("apply to all raw files.  You can force AIFF/WAVE files to be treated as raw\n");
+       printf("files using -fr.\n");
+       printf("\n");
+       printf("general options:\n");
+       printf("  -v, --version                Show the flac version number\n");
+       printf("  -h, --help                   Show basic usage a list of all options\n");
+       printf("  -H, --explain                Show this screen\n");
+       printf("  -d, --decode                 Decode (the default behavior is to encode)\n");
+       printf("  -t, --test                   Same as -d except no decoded file is written\n");
+       printf("  -a, --analyze                Same as -d except an analysis file is written\n");
+       printf("  -c, --stdout                 Write output to stdout\n");
+       printf("  -s, --silent                 Do not write runtime encode/decode statistics\n");
+       printf("      --totally-silent         Do not print anything of any kind, including\n");
+       printf("                               warnings or errors.  The exit code will be the\n");
+       printf("                               only way to determine successful completion.\n");
+       printf("      --no-utf8-convert        Do not convert tags from local charset to UTF-8.\n");
+       printf("                               This is useful for scripts, and setting tags in\n");
+       printf("                               situations where the locale is wrong.  This\n");
+       printf("                               option must appear before any tag options!\n");
+       printf("  -w, --warnings-as-errors     Treat all warnings as errors\n");
+       printf("  -f, --force                  Force overwriting of output files\n");
+       printf("  -o, --output-name=FILENAME   Force the output file name; usually flac just\n");
+       printf("                               changes the extension.  May only be used when\n");
+       printf("                               encoding a single file.  May not be used in\n");
+       printf("                               conjunction with --output-prefix.\n");
+       printf("      --output-prefix=STRING   Prefix each output file name with the given\n");
+       printf("                               STRING.  This can be useful for encoding or\n");
+       printf("                               decoding files to a different directory.  Make\n");
+       printf("                               sure if your STRING is a path name that it ends\n");
+       printf("                               with a '/' slash.\n");
+       printf("      --delete-input-file      Automatically delete the input file after a\n");
+       printf("                               successful encode or decode.  If there was an\n");
+       printf("                               error (including a verify error) the input file\n");
+       printf("                               is left intact.\n");
+       printf("      --keep-foreign-metadata  If encoding, save WAVE or AIFF non-audio chunks\n");
+       printf("                               in FLAC metadata.  If decoding, restore any saved\n");
+       printf("                               non-audio chunks from FLAC metadata when writing\n");
+       printf("                               the decoded file.  Foreign metadata cannot be\n");
+       printf("                               transcoded, e.g. WAVE chunks saved in a FLAC file\n");
+       printf("                               cannot be restored when decoding to AIFF.  Input\n");
+       printf("                               and output must be regular files, not stdin/out.\n");
+       printf("      --skip={#|mm:ss.ss}      Skip the first # samples of each input file; can\n");
+       printf("                               be used both for encoding and decoding.  The\n");
+       printf("                               alternative form mm:ss.ss can be used to specify\n");
+       printf("                               minutes, seconds, and fractions of a second.\n");
+       printf("      --until={#|[+|-]mm:ss.ss}  Stop at the given sample number for each input\n");
+       printf("                               file.  The given sample number is not included\n");
+       printf("                               in the decoded output.  The alternative form\n");
+       printf("                               mm:ss.ss can be used to specify minutes,\n");
+       printf("                               seconds, and fractions of a second.  If a `+'\n");
+       printf("                               sign is at the beginning, the --until point is\n");
+       printf("                               relative to the --skip point.  If a `-' sign is\n");
+       printf("                               at the beginning, the --until point is relative\n");
+       printf("                               to end of the audio.\n");
+#if FLAC__HAS_OGG
+       printf("      --ogg                    When encoding, generate Ogg FLAC output instead\n");
+       printf("                               of native FLAC.  Ogg FLAC streams are FLAC\n");
+       printf("                               streams wrapped in an Ogg transport layer.  The\n");
+       printf("                               resulting file should have an '.oga' extension\n");
+       printf("                               and will still be decodable by flac.  When\n");
+       printf("                               decoding, force the input to be treated as\n");
+       printf("                               Ogg FLAC.  This is useful when piping input\n");
+       printf("                               from stdin or when the filename does not end in\n");
+       printf("                               '.oga' or '.ogg'.\n");
+       printf("      --serial-number          Serial number to use for the FLAC stream.  When\n");
+       printf("                               encoding and no serial number is given, flac\n");
+       printf("                               uses a random one.  If encoding to multiple files\n");
+       printf("                               the serial number is incremented for each file.\n");
+       printf("                               When decoding and no number is given, flac uses\n");
+       printf("                               the serial number of the first page.\n");
+#endif
+       printf("analysis options:\n");
+       printf("      --residual-text          Include residual signal in text output.  This\n");
+       printf("                               will make the file very big, much larger than\n");
+       printf("                               even the decoded file.\n");
+       printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
+       printf("                               of each subframe\n");
+       printf("decoding options:\n");
+       printf("  -F, --decode-through-errors  By default flac stops decoding with an error\n");
+       printf("                               and removes the partially decoded file if it\n");
+       printf("                               encounters a bitstream error.  With -F, errors\n");
+       printf("                               are still printed but flac will continue\n");
+       printf("                               decoding to completion.  Note that errors may\n");
+       printf("                               cause the decoded audio to be missing some\n");
+       printf("                               samples or have silent sections.\n");
+       printf("      --cue=[#.#][-[#.#]]      Set the beginning and ending cuepoints to\n");
+       printf("                               decode.  The optional first #.# is the track and\n");
+       printf("                               index point at which decoding will start; the\n");
+       printf("                               default is the beginning of the stream.  The\n");
+       printf("                               optional second #.# is the track and index point\n");
+       printf("                               at which decoding will end; the default is the\n");
+       printf("                               end of the stream.  If the cuepoint does not\n");
+       printf("                               exist, the closest one before it (for the start\n");
+       printf("                               point) or after it (for the end point) will be\n");
+       printf("                               used.  The cuepoints are merely translated into\n");
+       printf("                               sample numbers then used as --skip and --until.\n");
+       printf("                               A CD track can always be cued by, for example,\n");
+       printf("                               --cue=9.1-10.1 for track 9, even if the CD has\n");
+       printf("                               no 10th track.\n");
+       printf("encoding options:\n");
+       printf("  -V, --verify                 Verify a correct encoding by decoding the\n");
+       printf("                               output in parallel and comparing to the\n");
+       printf("                               original\n");
+       printf("      --lax                    Allow encoder to generate non-Subset files\n");
+#if 0 /*@@@ currently undocumented */
+       printf("      --ignore-chunk-sizes     Ignore data chunk sizes in WAVE/AIFF files;\n");
+       printf("                               useful when piping data from programs which\n");
+       printf("                               generate bogus data chunk sizes.\n");
+#endif
+       printf("      --sector-align           Align encoding of multiple CD format WAVE files\n");
+       printf("                               on sector boundaries.\n");
+       printf("      --replay-gain            Calculate ReplayGain values and store them as\n");
+       printf("                               FLAC tags.  Title gains/peaks will be computed\n");
+       printf("                               for each file, and an album gain/peak will be\n");
+       printf("                               computed for all files.  All input files must\n");
+       printf("                               have the same resolution, sample rate, and\n");
+       printf("                               number of channels.  The sample rate must be\n");
+       printf("                               one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1,\n");
+       printf("                               or 48 kHz.  NOTE: this option may also leave a\n");
+       printf("                               few extra bytes in the PADDING block.\n");
+       printf("      --cuesheet=FILENAME      Import the given cuesheet file and store it in\n");
+       printf("                               a CUESHEET metadata block.  This option may only\n");
+       printf("                               be used when encoding a single file.  A\n");
+       printf("                               seekpoint will be added for each index point in\n");
+       printf("                               the cuesheet to the SEEKTABLE unless\n");
+       printf("                               --no-cued-seekpoints is specified.\n");
+       printf("      --picture=SPECIFICATION  Import a picture and store it in a PICTURE block.\n");
+       printf("                               More than one --picture command can be specified.\n");
+       printf("                               The SPECIFICATION can either be a simple filename\n");
+       printf("                               for the picture file, or a complete specification\n");
+       printf("                               whose parts are separated by | characters.  Some\n");
+       printf("                               parts may be left empty to invoke default values.\n");
+       printf("                               Using a filename is shorthand for \"||||FILE\".\n");
+       printf("                               The SPECIFICATION format is:\n");
+       printf("         [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n");
+       printf("           TYPE is optional; it is a number from one of:\n");
+       printf("              0: Other\n");
+       printf("              1: 32x32 pixels 'file icon' (PNG only)\n");
+       printf("              2: Other file icon\n");
+       printf("              3: Cover (front)\n");
+       printf("              4: Cover (back)\n");
+       printf("              5: Leaflet page\n");
+       printf("              6: Media (e.g. label side of CD)\n");
+       printf("              7: Lead artist/lead performer/soloist\n");
+       printf("              8: Artist/performer\n");
+       printf("              9: Conductor\n");
+       printf("             10: Band/Orchestra\n");
+       printf("             11: Composer\n");
+       printf("             12: Lyricist/text writer\n");
+       printf("             13: Recording Location\n");
+       printf("             14: During recording\n");
+       printf("             15: During performance\n");
+       printf("             16: Movie/video screen capture\n");
+       printf("             17: A bright coloured fish\n");
+       printf("             18: Illustration\n");
+       printf("             19: Band/artist logotype\n");
+       printf("             20: Publisher/Studio logotype\n");
+       printf("             The default is 3 (front cover).  There may only be one picture each\n");
+       printf("             of type 1 and 2 in a file.\n");
+       printf("           MIME-TYPE is optional; if left blank, it will be detected from the\n");
+       printf("             file.  For best compatibility with players, use pictures with MIME\n");
+       printf("             type image/jpeg or image/png.  The MIME type can also be --> to\n");
+       printf("             mean that FILE is actually a URL to an image, though this use is\n");
+       printf("             discouraged.\n");
+       printf("           DESCRIPTION is optional; the default is an empty string\n");
+       printf("           The next part specfies the resolution and color information.  If\n");
+       printf("             the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n");
+       printf("             usually leave this empty and they can be detected from the file.\n");
+       printf("             Otherwise, you must specify the width in pixels, height in pixels,\n");
+       printf("             and color depth in bits-per-pixel.  If the image has indexed colors\n");
+       printf("             you should also specify the number of colors used.\n");
+       printf("           FILE is the path to the picture file to be imported, or the URL if\n");
+       printf("             MIME type is -->\n");
+       printf("  -T, --tag=FIELD=VALUE        Add a FLAC tag.  Make sure to quote the\n");
+       printf("                               comment if necessary.  This option may appear\n");
+       printf("                               more than once to add several comments.  NOTE:\n");
+       printf("                               all tags will be added to all encoded files.\n");
+       printf("      --tag-from-file=FIELD=FILENAME   Like --tag, except FILENAME is a file\n");
+       printf("                               whose contents will be read verbatim to set the\n");
+       printf("                               tag value.  The contents will be converted to\n");
+       printf("                               UTF-8 from the local charset.  This can be used\n");
+       printf("                               to store a cuesheet in a tag (e.g.\n");
+       printf("                               --tag-from-file=\"CUESHEET=image.cue\").  Do not\n");
+       printf("                               try to store binary data in tag fields!  Use\n");
+       printf("                               APPLICATION blocks for that.\n");
+       printf("  -S, --seekpoint={#|X|#x|#s}  Include a point or points in a SEEKTABLE\n");
+       printf("       #  : a specific sample number for a seek point\n");
+       printf("       X  : a placeholder point (always goes at the end of the SEEKTABLE)\n");
+       printf("       #x : # evenly spaced seekpoints, the first being at sample 0\n");
+       printf("       #s : a seekpoint every # seconds; # does not have to be a whole number\n");
+       printf("     You may use many -S options; the resulting SEEKTABLE will be the unique-\n");
+       printf("           ified union of all such values.\n");
+       printf("     With no -S options, flac defaults to '-S 10s'.  Use -S- for no SEEKTABLE.\n");
+       printf("     Note: -S #x and -S #s will not work if the encoder can't determine the\n");
+       printf("           input size before starting.\n");
+       printf("     Note: if you use -S # and # is >= samples in the input, there will be\n");
+       printf("           either no seek point entered (if the input size is determinable\n");
+       printf("           before encoding starts) or a placeholder point (if input size is not\n");
+       printf("           determinable)\n");
+       printf("  -P, --padding=#              Tell the encoder to write a PADDING metadata\n");
+       printf("                               block of the given length (in bytes) after the\n");
+       printf("                               STREAMINFO block.  This is useful if you plan\n");
+       printf("                               to tag the file later with an APPLICATION\n");
+       printf("                               block; instead of having to rewrite the entire\n");
+       printf("                               file later just to insert your block, you can\n");
+       printf("                               write directly over the PADDING block.  Note\n");
+       printf("                               that the total length of the PADDING block will\n");
+       printf("                               be 4 bytes longer than the length given because\n");
+       printf("                               of the 4 metadata block header bytes.  You can\n");
+       printf("                               force no PADDING block at all to be written with\n");
+       printf("                               --no-padding.  The encoder writes a PADDING\n");
+       printf("                               block of 8192 bytes by default, or 65536 bytes\n");
+       printf("                               if the input audio is more than 20 minutes long.\n");
+       printf("  -b, --blocksize=#            Specify the blocksize in samples; the default is\n");
+       printf("                               1152 for -l 0, else 4096; must be one of 192,\n");
+       printf("                               576, 1152, 2304, 4608, 256, 512, 1024, 2048,\n");
+       printf("                               4096 (and 8192 or 16384 if the sample rate is\n");
+       printf("                               >48kHz) for Subset streams.\n");
+       printf("  -0, --compression-level-0, --fast  Synonymous with -l 0 -b 1152 -r 3\n");
+       printf("  -1, --compression-level-1          Synonymous with -l 0 -b 1152 -M -r 3\n");
+       printf("  -2, --compression-level-2          Synonymous with -l 0 -b 1152 -m -r 3\n");
+       printf("  -3, --compression-level-3          Synonymous with -l 6 -b 4096 -r 4\n");
+       printf("  -4, --compression-level-4          Synonymous with -l 8 -b 4096 -M -r 4\n");
+       printf("  -5, --compression-level-5          Synonymous with -l 8 -b 4096 -m -r 5\n");
+       printf("                                     -5 is the default setting\n");
+       printf("  -6, --compression-level-6          Synonymous with -l 8 -b 4096 -m -r 6\n");
+       printf("  -7, --compression-level-7          Synonymous with -l 8 -b 4096 -m -e -r 6\n");
+       printf("  -8, --compression-level-8, --best  Synonymous with -l 12 -b 4096 -m -e -r 6\n");
+       printf("  -m, --mid-side                     Try mid-side coding for each frame\n");
+       printf("                                     (stereo only)\n");
+       printf("  -M, --adaptive-mid-side            Adaptive mid-side coding for all frames\n");
+       printf("                                     (stereo only)\n");
+       printf("  -e, --exhaustive-model-search      Do exhaustive model search (expensive!)\n");
+       printf("  -A, --apodization=\"function\"       Window audio data with given the function.\n");
+       printf("                                     The functions are: bartlett, bartlett_hann,\n");
+       printf("                                     blackman, blackman_harris_4term_92db,\n");
+       printf("                                     connes, flattop, gauss(STDDEV), hamming,\n");
+       printf("                                     hann, kaiser_bessel, nuttall, rectangle,\n");
+       printf("                                     triangle, tukey(P), welch.  More than one\n");
+       printf("                                     may be specified but encoding time is a\n");
+       printf("                                     multiple of the number of functions since\n");
+       printf("                                     they are each tried in turn.  The encoder\n");
+       printf("                                     chooses suitable defaults in the absence\n");
+       printf("                                     of any -A options.\n");
+       printf("  -l, --max-lpc-order=#              Max LPC order; 0 => only fixed predictors.\n");
+       printf("                                     Must be <= 12 for Subset streams if sample\n");
+       printf("                                     rate is <=48kHz.\n");
+       printf("  -p, --qlp-coeff-precision-search   Do exhaustive search of LP coefficient\n");
+       printf("                                     quantization (expensive!); overrides -q;\n");
+       printf("                                     does nothing if using -l 0\n");
+       printf("  -q, --qlp-coeff-precision=#        Specify precision in bits of quantized\n");
+       printf("                                     linear-predictor coefficients; 0 => let\n");
+       printf("                                     encoder decide (the minimun is %u, the\n", FLAC__MIN_QLP_COEFF_PRECISION);
+       printf("                                     default is -q 0)\n");
+       printf("  -r, --rice-partition-order=[#,]#   Set [min,]max residual partition order\n");
+       printf("                                     (# is 0..16; min defaults to 0; the\n");
+       printf("                                     default is -r 0; above 4 doesn't usually\n");
+       printf("                                     help much)\n");
+       printf("format options:\n");
+       printf("      --endian={big|little}    Set byte order for samples\n");
+       printf("      --channels=#             Number of channels\n");
+       printf("      --bps=#                  Number of bits per sample\n");
+       printf("      --sample-rate=#          Sample rate in Hz\n");
+       printf("      --sign={signed|unsigned} Sign of samples (the default is signed)\n");
+       printf("      --input-size=#           Size of the raw input in bytes.  If you are\n");
+       printf("                               encoding raw samples from stdin, you must set\n");
+       printf("                               this option in order to be able to use --skip,\n");
+       printf("                               --until, --cue-sheet, or other options that need\n");
+       printf("                               to know the size of the input beforehand.  If\n");
+       printf("                               the size given is greater than what is found in\n");
+       printf("                               the input stream, the encoder will complain\n");
+       printf("                               about an unexpected end-of-file.  If the size\n");
+       printf("                               given is less, samples will be truncated.\n");
+       printf("      --force-aiff-format      Force the decoder to output AIFF format.  This\n");
+       printf("                               option is not needed if the output filename (as\n");
+       printf("                               set by -o) ends with .aif or .aiff; this option\n");
+       printf("                               has no effect when encoding since input AIFF is\n");
+       printf("                               auto-detected.\n");
+       printf("      --force-raw-format       Force input (when encoding) or output (when\n");
+       printf("                               decoding) to be treated as raw samples\n");
+       printf("negative options:\n");
+       printf("      --no-adaptive-mid-side\n");
+       printf("      --no-decode-through-errors\n");
+       printf("      --no-delete-input-file\n");
+       printf("      --no-keep-foreign-metadata\n");
+       printf("      --no-exhaustive-model-search\n");
+       printf("      --no-lax\n");
+       printf("      --no-mid-side\n");
+#if FLAC__HAS_OGG
+       printf("      --no-ogg\n");
+#endif
+       printf("      --no-padding\n");
+       printf("      --no-qlp-coeff-prec-search\n");
+       printf("      --no-residual-gnuplot\n");
+       printf("      --no-residual-text\n");
+#if 0 /*@@@ currently undocumented */
+       printf("      --no-ignore-chunk-sizes\n");
+#endif
+       printf("      --no-sector-align\n");
+       printf("      --no-seektable\n");
+       printf("      --no-silent\n");
+       printf("      --no-force\n");
+       printf("      --no-verify\n");
+       printf("      --no-warnings-as-errors\n");
+}
+
+void format_mistake(const char *infilename, FileFormat wrong, FileFormat right)
+{
+       /* WATCHOUT: indexed by FileFormat */
+       static const char * const ff[] = { "raw", "WAVE", "AIFF", "FLAC", "Ogg FLAC" };
+       flac__utils_printf(stderr, 1, "WARNING: %s is not a %s file; treating as a %s file\n", infilename, ff[wrong], ff[right]);
+}
+
+int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file)
+{
+       FILE *encode_infile;
+       FLAC__byte lookahead[12];
+       unsigned lookahead_length = 0;
+       FileFormat input_format = RAW;
+       FLAC__bool is_aifc = false;
+       int retval;
+       off_t infilesize;
+       encode_options_t common_options;
+       const char *outfilename = get_encoded_outfilename(infilename); /* the final name of the encoded file */
+       /* internal_outfilename is the file we will actually write to; it will be a temporary name if infilename==outfilename */
+       char *internal_outfilename = 0; /* NULL implies 'use outfilename' */
+
+       if(0 == outfilename) {
+               flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+               return 1;
+       }
+
+       if(0 == strcmp(infilename, "-")) {
+               infilesize = (off_t)(-1);
+               encode_infile = grabbag__file_get_binary_stdin();
+       }
+       else {
+               infilesize = grabbag__file_get_filesize(infilename);
+               if(0 == (encode_infile = fopen(infilename, "rb"))) {
+                       flac__utils_printf(stderr, 1, "ERROR: can't open input file %s: %s\n", infilename, strerror(errno));
+                       return 1;
+               }
+       }
+
+       if(!option_values.force_raw_format) {
+               /* first set format based on name */
+               if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".wav"))
+                       input_format = WAV;
+               else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".aif"))
+                       input_format = AIF;
+               else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".aiff"))
+                       input_format = AIF;
+               else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".flac"))
+                       input_format = FLAC;
+               else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".oga"))
+                       input_format = OGGFLAC;
+               else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".ogg"))
+                       input_format = OGGFLAC;
+
+               /* attempt to guess the file type based on the first 12 bytes */
+               if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) {
+                       if(input_format != RAW) {
+                               format_mistake(infilename, input_format, RAW);
+                               if(option_values.treat_warnings_as_errors) {
+                                       conditional_fclose(encode_infile);
+                                       return 1;
+                               }
+                       }
+                       input_format = RAW;
+               }
+               else {
+                       if(!strncmp((const char *)lookahead, "ID3", 3)) {
+                               flac__utils_printf(stderr, 1, "ERROR: input file %s has an ID3v2 tag\n", infilename);
+                               return 1;
+                       }
+                       else if(!strncmp((const char *)lookahead, "RIFF", 4) && !strncmp((const char *)lookahead+8, "WAVE", 4))
+                               input_format = WAV;
+                       else if(!strncmp((const char *)lookahead, "FORM", 4) && !strncmp((const char *)lookahead+8, "AIFF", 4))
+                               input_format = AIF;
+                       else if(!strncmp((const char *)lookahead, "FORM", 4) && !strncmp((const char *)lookahead+8, "AIFC", 4)) {
+                               input_format = AIF;
+                               is_aifc = true;
+                       }
+                       else if(!memcmp(lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING)))
+                               input_format = FLAC;
+                       /* this could be made more accurate by looking at the first packet */
+                       else if(!memcmp(lookahead, "OggS", 4))
+                               input_format = OGGFLAC;
+                       else {
+                               if(input_format != RAW) {
+                                       format_mistake(infilename, input_format, RAW);
+                                       if(option_values.treat_warnings_as_errors) {
+                                               conditional_fclose(encode_infile);
+                                               return 1;
+                                       }
+                               }
+                               input_format = RAW;
+                       }
+               }
+       }
+
+       if(option_values.keep_foreign_metadata) {
+               if(encode_infile == stdin || option_values.force_to_stdout) {
+                       conditional_fclose(encode_infile);
+                       return usage_error("ERROR: --keep-foreign-metadata cannot be used when encoding from stdin or to stdout\n");
+               }
+               if(input_format != WAV && input_format != AIF) {
+                       conditional_fclose(encode_infile);
+                       return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE or AIFF input\n");
+               }
+       }
+
+       /*
+        * Error if output file already exists (and -f not used).
+        * Use grabbag__file_get_filesize() as a cheap way to check.
+        */
+       if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) {
+               if(input_format == FLAC) {
+                       /* need more detailed error message when re-flac'ing to avoid confusing the user */
+                       flac__utils_printf(stderr, 1,
+                               "ERROR: output file %s already exists.\n\n"
+                               "By default flac encodes files to FLAC format; if you meant to decode this file\n"
+                               "from FLAC to something else, use -d.  If you meant to re-encode this file from\n"
+                               "FLAC to FLAC again, use -f to force writing to the same file, or -o to specify\n"
+                               "a different output filename.\n",
+                               outfilename
+                       );
+               }
+               else if(input_format == OGGFLAC) {
+                       /* need more detailed error message when re-flac'ing to avoid confusing the user */
+                       flac__utils_printf(stderr, 1,
+                               "ERROR: output file %s already exists.\n\n"
+                               "By default 'flac -ogg' encodes files to Ogg FLAC format; if you meant to decode\n"
+                               "this file from Ogg FLAC to something else, use -d.  If you meant to re-encode\n"
+                               "this file from Ogg FLAC to Ogg FLAC again, use -f to force writing to the same\n"
+                               "file, or -o to specify a different output filename.\n",
+                               outfilename
+                       );
+               }
+               else
+                       flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
+               conditional_fclose(encode_infile);
+               return 1;
+       }
+
+       if(option_values.format_input_size >= 0) {
+               if (input_format != RAW || infilesize >= 0) {
+                       flac__utils_printf(stderr, 1, "ERROR: can only use --input-size when encoding raw samples from stdin\n");
+                       conditional_fclose(encode_infile);
+                       return 1;
+               }
+               else {
+                       infilesize = option_values.format_input_size;
+               }
+       }
+
+       if(option_values.sector_align && (input_format == FLAC || input_format == OGGFLAC)) {
+               flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input file is FLAC or Ogg FLAC\n");
+               conditional_fclose(encode_infile);
+               return 1;
+       }
+       if(option_values.sector_align && input_format == RAW && infilesize < 0) {
+               flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input size is unknown\n");
+               conditional_fclose(encode_infile);
+               return 1;
+       }
+
+       if(input_format == RAW) {
+               if(option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0 || option_values.format_channels < 0 || option_values.format_bps < 0 || option_values.format_sample_rate < 0) {
+                       conditional_fclose(encode_infile);
+                       return usage_error("ERROR: for encoding a raw file you must specify a value for --endian, --sign, --channels, --bps, and --sample-rate\n");
+               }
+       }
+
+       if(/*@@@@@@why no stdin?*/encode_infile == stdin || option_values.force_to_stdout) {
+               if(option_values.replay_gain) {
+                       conditional_fclose(encode_infile);
+                       return usage_error("ERROR: --replay-gain cannot be used when encoding to stdout\n");
+               }
+       }
+       if(option_values.replay_gain && option_values.use_ogg) {
+               conditional_fclose(encode_infile);
+               return usage_error("ERROR: --replay-gain cannot be used when encoding to Ogg FLAC yet\n");
+       }
+
+       if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &common_options.skip_specification) || common_options.skip_specification.is_relative) {
+               conditional_fclose(encode_infile);
+               return usage_error("ERROR: invalid value for --skip\n");
+       }
+
+       if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &common_options.until_specification)) { /*@@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */
+               conditional_fclose(encode_infile);
+               return usage_error("ERROR: invalid value for --until\n");
+       }
+       /* if there is no "--until" we want to default to "--until=-0" */
+       if(0 == option_values.until_specification)
+               common_options.until_specification.is_relative = true;
+
+       common_options.verify = option_values.verify;
+       common_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+#if FLAC__HAS_OGG
+       common_options.use_ogg = option_values.use_ogg;
+       /* set a random serial number if one has not yet been specified */
+       if(!option_values.has_serial_number) {
+               option_values.serial_number = rand();
+               option_values.has_serial_number = true;
+       }
+       common_options.serial_number = option_values.serial_number++;
+#endif
+       common_options.lax = option_values.lax;
+       common_options.padding = option_values.padding;
+       common_options.num_compression_settings = option_values.num_compression_settings;
+       FLAC__ASSERT(sizeof(common_options.compression_settings) >= sizeof(option_values.compression_settings));
+       memcpy(common_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings));
+       common_options.requested_seek_points = option_values.requested_seek_points;
+       common_options.num_requested_seek_points = option_values.num_requested_seek_points;
+       common_options.cuesheet_filename = option_values.cuesheet_filename;
+       common_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+       common_options.cued_seekpoints = option_values.cued_seekpoints;
+       common_options.channel_map_none = option_values.channel_map_none;
+       common_options.is_first_file = is_first_file;
+       common_options.is_last_file = is_last_file;
+       common_options.align_reservoir = align_reservoir;
+       common_options.align_reservoir_samples = &align_reservoir_samples;
+       common_options.replay_gain = option_values.replay_gain;
+       common_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes;
+       common_options.sector_align = option_values.sector_align;
+       common_options.vorbis_comment = option_values.vorbis_comment;
+       FLAC__ASSERT(sizeof(common_options.pictures) >= sizeof(option_values.pictures));
+       memcpy(common_options.pictures, option_values.pictures, sizeof(option_values.pictures));
+       common_options.num_pictures = option_values.num_pictures;
+       common_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes;
+       common_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes;
+       common_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes;
+       common_options.debug.do_md5 = option_values.debug.do_md5;
+
+       /* if infilename and outfilename point to the same file, we need to write to a temporary file */
+       if(encode_infile != stdin && grabbag__file_are_same(infilename, outfilename)) {
+               static const char *tmp_suffix = ".tmp,fl-ac+en'c";
+               /*@@@@ still a remote possibility that a file with this filename exists */
+               if(0 == (internal_outfilename = (char *)safe_malloc_add_3op_(strlen(outfilename), /*+*/strlen(tmp_suffix), /*+*/1))) {
+                       flac__utils_printf(stderr, 1, "ERROR allocating memory for tempfile name\n");
+                       conditional_fclose(encode_infile);
+                       return 1;
+               }
+               strcpy(internal_outfilename, outfilename);
+               strcat(internal_outfilename, tmp_suffix);
+       }
+
+       if(input_format == RAW) {
+               raw_encode_options_t options;
+
+               options.common = common_options;
+               options.is_big_endian = option_values.format_is_big_endian;
+               options.is_unsigned_samples = option_values.format_is_unsigned_samples;
+               options.channels = option_values.format_channels;
+               options.bps = option_values.format_bps;
+               options.sample_rate = option_values.format_sample_rate;
+
+               retval = flac__encode_raw(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options);
+       }
+       else if(input_format == FLAC || input_format == OGGFLAC) {
+               flac_encode_options_t options;
+
+               options.common = common_options;
+
+               retval = flac__encode_flac(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, input_format==OGGFLAC);
+       }
+       else {
+               wav_encode_options_t options;
+
+               options.common = common_options;
+               options.foreign_metadata = 0;
+
+               /* read foreign metadata if requested */
+               if(option_values.keep_foreign_metadata) {
+                       if(0 == (options.foreign_metadata = flac__foreign_metadata_new(input_format==AIF? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
+                               flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+                               conditional_fclose(encode_infile);
+                               return 1;
+                       }
+               }
+
+               if(input_format == AIF)
+                       retval = flac__encode_aif(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, is_aifc);
+               else
+                       retval = flac__encode_wav(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options);
+
+               if(options.foreign_metadata)
+                       flac__foreign_metadata_delete(options.foreign_metadata);
+       }
+
+       if(retval == 0) {
+               if(strcmp(outfilename, "-")) {
+                       if(option_values.replay_gain) {
+                               float title_gain, title_peak;
+                               const char *error;
+                               grabbag__replaygain_get_title(&title_gain, &title_peak);
+                               if(
+                                       0 != (error = grabbag__replaygain_store_to_file_reference(internal_outfilename? internal_outfilename : outfilename, /*preserve_modtime=*/true)) ||
+                                       0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename? internal_outfilename : outfilename, title_gain, title_peak, /*preserve_modtime=*/true))
+                               ) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain reference/title tags (%s)\n", outfilename, error);
+                                       retval = 1;
+                               }
+                       }
+                       if(strcmp(infilename, "-"))
+                               grabbag__file_copy_metadata(infilename, internal_outfilename? internal_outfilename : outfilename);
+               }
+       }
+
+       /* rename temporary file if necessary */
+       if(retval == 0 && internal_outfilename != 0) {
+               if(rename(internal_outfilename, outfilename) < 0) {
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+                       /* on some flavors of windows, rename() will fail if the destination already exists, so we unlink and try again */
+                       if(unlink(outfilename) < 0) {
+                               flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename);
+                               retval = 1;
+                       }
+                       else if(rename(internal_outfilename, outfilename) < 0) {
+                               flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, you must do it\n", internal_outfilename, outfilename);
+                               retval = 1;
+                       }
+#else
+                       flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename);
+                       retval = 1;
+#endif
+               }
+       }
+
+       /* handle --delete-input-file, but don't want to delete if piping from stdin, or if input filename and output filename are the same */
+       if(retval == 0 && option_values.delete_input && strcmp(infilename, "-") && internal_outfilename == 0)
+               unlink(infilename);
+
+       if(internal_outfilename != 0)
+               free(internal_outfilename);
+
+       return retval;
+}
+
+int decode_file(const char *infilename)
+{
+       int retval;
+       FLAC__bool treat_as_ogg = false;
+       FileFormat output_format = WAV;
+       decode_options_t common_options;
+       const char *outfilename = get_decoded_outfilename(infilename);
+
+       if(0 == outfilename) {
+               flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+               return 1;
+       }
+
+       /*
+        * Error if output file already exists (and -f not used).
+        * Use grabbag__file_get_filesize() as a cheap way to check.
+        */
+       if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) {
+               flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
+               return 1;
+       }
+
+       if(option_values.force_raw_format)
+               output_format = RAW;
+       else if(
+               option_values.force_aiff_format ||
+               (strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".aif")) ||
+               (strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".aiff"))
+       )
+               output_format = AIF;
+       else
+               output_format = WAV;
+
+       if(!option_values.test_only && !option_values.analyze) {
+               if(output_format == RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0))
+                       return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n");
+       }
+
+       if(option_values.keep_foreign_metadata) {
+               if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-"))
+                       return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n");
+               if(output_format != WAV && output_format != AIF)
+                       return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE or AIFF output\n");
+       }
+
+       if(option_values.use_ogg)
+               treat_as_ogg = true;
+       else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".oga"))
+               treat_as_ogg = true;
+       else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".ogg"))
+               treat_as_ogg = true;
+       else
+               treat_as_ogg = false;
+
+#if !FLAC__HAS_OGG
+       if(treat_as_ogg) {
+               flac__utils_printf(stderr, 1, "%s: Ogg support has not been built into this copy of flac\n", infilename);
+               return 1;
+       }
+#endif
+
+       if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &common_options.skip_specification) || common_options.skip_specification.is_relative)
+               return usage_error("ERROR: invalid value for --skip\n");
+
+       if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &common_options.until_specification)) /*@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */
+               return usage_error("ERROR: invalid value for --until\n");
+       /* if there is no "--until" we want to default to "--until=-0" */
+       if(0 == option_values.until_specification)
+               common_options.until_specification.is_relative = true;
+
+       if(option_values.cue_specification) {
+               if(!flac__utils_parse_cue_specification(option_values.cue_specification, &common_options.cue_specification))
+                       return usage_error("ERROR: invalid value for --cue\n");
+               common_options.has_cue_specification = true;
+       }
+       else
+               common_options.has_cue_specification = false;
+
+       common_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+       common_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+       common_options.replaygain_synthesis_spec = option_values.replaygain_synthesis_spec;
+#if FLAC__HAS_OGG
+       common_options.is_ogg = treat_as_ogg;
+       common_options.use_first_serial_number = !option_values.has_serial_number;
+       common_options.serial_number = option_values.serial_number;
+#endif
+       common_options.channel_map_none = option_values.channel_map_none;
+
+       if(output_format == RAW) {
+               raw_decode_options_t options;
+
+               options.common = common_options;
+               options.is_big_endian = option_values.format_is_big_endian;
+               options.is_unsigned_samples = option_values.format_is_unsigned_samples;
+
+               retval = flac__decode_raw(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options);
+       }
+       else {
+               wav_decode_options_t options;
+
+               options.common = common_options;
+               options.foreign_metadata = 0;
+
+               /* read foreign metadata if requested */
+               if(option_values.keep_foreign_metadata) {
+                       if(0 == (options.foreign_metadata = flac__foreign_metadata_new(output_format==AIF? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
+                               flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+                               return 1;
+                       }
+               }
+
+               if(output_format == AIF)
+                       retval = flac__decode_aiff(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options);
+               else
+                       retval = flac__decode_wav(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options);
+
+               if(options.foreign_metadata)
+                       flac__foreign_metadata_delete(options.foreign_metadata);
+       }
+
+       if(retval == 0 && strcmp(infilename, "-")) {
+               if(strcmp(outfilename, "-"))
+                       grabbag__file_copy_metadata(infilename, outfilename);
+               if(option_values.delete_input && !option_values.test_only && !option_values.analyze)
+                       unlink(infilename);
+       }
+
+       return retval;
+}
+
+const char *get_encoded_outfilename(const char *infilename)
+{
+       const char *suffix = (option_values.use_ogg? ".oga" : ".flac");
+       return get_outfilename(infilename, suffix);
+}
+
+const char *get_decoded_outfilename(const char *infilename)
+{
+       const char *suffix;
+       if(option_values.analyze) {
+               suffix = ".ana";
+       }
+       else if(option_values.force_raw_format) {
+               suffix = ".raw";
+       }
+       else if(option_values.force_aiff_format) {
+               suffix = ".aiff";
+       }
+       else {
+               suffix = ".wav";
+       }
+       return get_outfilename(infilename, suffix);
+}
+
+const char *get_outfilename(const char *infilename, const char *suffix)
+{
+       if(0 == option_values.cmdline_forced_outfilename) {
+               static char buffer[4096]; /* @@@ bad MAGIC NUMBER */
+
+               if(0 == strcmp(infilename, "-") || option_values.force_to_stdout) {
+                       strcpy(buffer, "-");
+               }
+               else {
+                       char *p;
+                       if (flac__strlcpy(buffer, option_values.output_prefix? option_values.output_prefix : "", sizeof buffer) >= sizeof buffer)
+                               return 0;
+                       if (flac__strlcat(buffer, infilename, sizeof buffer) >= sizeof buffer)
+                               return 0;
+                       /* the . must come after any / to avoid problems with, e.g. "some.directory/extensionless-filename" */
+                       if(0 == (p = strrchr(buffer, '.')) || strchr(p, '/')) {
+                               if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer)
+                                       return 0;
+                       }
+                       else {
+                               *p = '\0';
+                               if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer)
+                                       return 0;
+                       }
+               }
+               return buffer;
+       }
+       else
+               return option_values.cmdline_forced_outfilename;
+}
+
+void die(const char *message)
+{
+       FLAC__ASSERT(0 != message);
+       flac__utils_printf(stderr, 1, "ERROR: %s\n", message);
+       exit(1);
+}
+
+int conditional_fclose(FILE *f)
+{
+       if(f == 0 || f == stdin || f == stdout)
+               return 0;
+       else
+               return fclose(f);
+}
+
+char *local_strdup(const char *source)
+{
+       char *ret;
+       FLAC__ASSERT(0 != source);
+       if(0 == (ret = strdup(source)))
+               die("out of memory during strdup()");
+       return ret;
+}
+
+#ifdef _MSC_VER
+/* There's no strtoll() in MSVC6 so we just write a specialized one */
+FLAC__int64 local__strtoll(const char *src, char **endptr)
+{
+       FLAC__bool neg = false;
+       FLAC__int64 ret = 0;
+       int c;
+       FLAC__ASSERT(0 != src);
+       if(*src == '-') {
+               neg = true;
+               src++;
+       }
+       while(0 != (c = *src)) {
+               c -= '0';
+               if(c >= 0 && c <= 9)
+                       ret = (ret * 10) + c;
+               else
+                       break;
+               src++;
+       }
+       if(endptr)
+               *endptr = (char*)src;
+       return neg? -ret : ret;
+}
+#endif
diff --git a/src/flac/utils.c b/src/flac/utils.c
new file mode 100644 (file)
index 0000000..bca8af7
--- /dev/null
@@ -0,0 +1,316 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
+
+int flac__utils_verbosity_ = 2;
+
+static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value)
+{
+       FLAC__uint64 ret = 0;
+       char c;
+
+       if(*s == '\0')
+               return false;
+
+       while('\0' != (c = *s++))
+               if(c >= '0' && c <= '9')
+                       ret = ret * 10 + (c - '0');
+               else
+                       return false;
+
+       *value = ret;
+       return true;
+}
+
+static FLAC__bool local__parse_timecode_(const char *s, double *value)
+{
+       double ret;
+       unsigned i;
+       char c;
+
+       /* parse [0-9][0-9]*: */
+       c = *s++;
+       if(c >= '0' && c <= '9')
+               i = (c - '0');
+       else
+               return false;
+       while(':' != (c = *s++)) {
+               if(c >= '0' && c <= '9')
+                       i = i * 10 + (c - '0');
+               else
+                       return false;
+       }
+       ret = (double)i * 60.;
+
+       /* parse [0-9]*[.,]?[0-9]* i.e. a sign-less rational number (. or , OK for fractional seconds, to support different locales) */
+       if(strspn(s, "1234567890.,") != strlen(s))
+               return false;
+       {
+               const char *p = strpbrk(s, ".,");
+               if(p && 0 != strpbrk(++p, ".,"))
+                       return false;
+       }
+       ret += atof(s);
+
+       *value = ret;
+       return true;
+}
+
+static FLAC__bool local__parse_cue_(const char *s, const char *end, unsigned *track, unsigned *index)
+{
+       FLAC__bool got_track = false, got_index = false;
+       unsigned t = 0, i = 0;
+       char c;
+
+       while(end? s < end : *s != '\0') {
+               c = *s++;
+               if(c >= '0' && c <= '9') {
+                       t = t * 10 + (c - '0');
+                       got_track = true;
+               }
+               else if(c == '.')
+                       break;
+               else
+                       return false;
+       }
+       while(end? s < end : *s != '\0') {
+               c = *s++;
+               if(c >= '0' && c <= '9') {
+                       i = i * 10 + (c - '0');
+                       got_index = true;
+               }
+               else
+                       return false;
+       }
+       *track = t;
+       *index = i;
+       return got_track && got_index;
+}
+
+/*
+ * this only works with sorted cuesheets (the spec strongly recommends but
+ * does not require sorted cuesheets).  but if it's not sorted, picking a
+ * nearest cue point has no significance.
+ */
+static FLAC__uint64 local__find_closest_cue_(const FLAC__StreamMetadata_CueSheet *cuesheet, unsigned track, unsigned index, FLAC__uint64 total_samples, FLAC__bool look_forward)
+{
+       int t, i;
+       if(look_forward) {
+               for(t = 0; t < (int)cuesheet->num_tracks; t++)
+                       for(i = 0; i < (int)cuesheet->tracks[t].num_indices; i++)
+                               if(cuesheet->tracks[t].number > track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number >= index))
+                                       return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset;
+               return total_samples;
+       }
+       else {
+               for(t = (int)cuesheet->num_tracks - 1; t >= 0; t--)
+                       for(i = (int)cuesheet->tracks[t].num_indices - 1; i >= 0; i--)
+                               if(cuesheet->tracks[t].number < track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number <= index))
+                                       return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset;
+               return 0;
+       }
+}
+
+void flac__utils_printf(FILE *stream, int level, const char *format, ...)
+{
+       if(flac__utils_verbosity_ >= level) {
+               va_list args;
+
+               FLAC__ASSERT(0 != format);
+
+               va_start(args, format);
+
+               (void) vfprintf(stream, format, args);
+
+               va_end(args);
+       }
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#endif
+
+FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec)
+{
+       FLAC__uint64 val;
+       FLAC__bool is_negative = false;
+
+       FLAC__ASSERT(0 != spec);
+
+       spec->is_relative = false;
+       spec->value_is_samples = true;
+       spec->value.samples = 0;
+
+       if(0 != s) {
+               if(s[0] == '-') {
+                       is_negative = true;
+                       spec->is_relative = true;
+                       s++;
+               }
+               else if(s[0] == '+') {
+                       spec->is_relative = true;
+                       s++;
+               }
+
+               if(local__parse_uint64_(s, &val)) {
+                       spec->value_is_samples = true;
+                       spec->value.samples = (FLAC__int64)val;
+                       if(is_negative)
+                               spec->value.samples = -(spec->value.samples);
+               }
+               else {
+                       double d;
+                       if(!local__parse_timecode_(s, &d))
+                               return false;
+                       spec->value_is_samples = false;
+                       spec->value.seconds = d;
+                       if(is_negative)
+                               spec->value.seconds = -(spec->value.seconds);
+               }
+       }
+
+       return true;
+}
+
+void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, unsigned sample_rate)
+{
+       FLAC__ASSERT(0 != spec);
+       if(!spec->value_is_samples) {
+               spec->value.samples = (FLAC__int64)(spec->value.seconds * (double)sample_rate);
+               spec->value_is_samples = true;
+       }
+}
+
+FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec)
+{
+       const char *start = s, *end = 0;
+
+       FLAC__ASSERT(0 != spec);
+
+       spec->has_start_point = spec->has_end_point = false;
+
+       s = strchr(s, '-');
+
+       if(0 != s) {
+               if(s == start)
+                       start = 0;
+               end = s+1;
+               if(*end == '\0')
+                       end = 0;
+       }
+
+       if(start) {
+               if(!local__parse_cue_(start, s, &spec->start_track, &spec->start_index))
+                       return false;
+               spec->has_start_point = true;
+       }
+
+       if(end) {
+               if(!local__parse_cue_(end, 0, &spec->end_track, &spec->end_index))
+                       return false;
+               spec->has_end_point = true;
+       }
+
+       return true;
+}
+
+void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec)
+{
+       FLAC__ASSERT(0 != cue_spec);
+       FLAC__ASSERT(0 != cuesheet);
+       FLAC__ASSERT(0 != total_samples);
+       FLAC__ASSERT(0 != skip_spec);
+       FLAC__ASSERT(0 != until_spec);
+
+       skip_spec->is_relative = false;
+       skip_spec->value_is_samples = true;
+
+       until_spec->is_relative = false;
+       until_spec->value_is_samples = true;
+
+       if(cue_spec->has_start_point)
+               skip_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->start_track, cue_spec->start_index, total_samples, /*look_forward=*/false);
+       else
+               skip_spec->value.samples = 0;
+
+       if(cue_spec->has_end_point)
+               until_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->end_track, cue_spec->end_index, total_samples, /*look_forward=*/true);
+       else
+               until_spec->value.samples = total_samples;
+}
+
+FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask)
+{
+       FLAC__StreamMetadata_VorbisComment_Entry entry = { 0, 0 };
+       char tag[128];
+
+       FLAC__ASSERT(object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(strlen(CHANNEL_MASK_TAG+1+2+16+1) <= sizeof(tag)); /* +1 for =, +2 for 0x, +16 for digits, +1 for NUL */
+       entry.entry = (FLAC__byte*)tag;
+#if defined _MSC_VER || defined __MINGW32__
+       if((entry.length = _snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (unsigned)channel_mask)) >= sizeof(tag))
+#else
+       if((entry.length = snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (unsigned)channel_mask)) >= sizeof(tag))
+#endif
+               return false;
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(object, entry, /*all=*/true, /*copy=*/true))
+               return false;
+       return true;
+}
+
+FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask)
+{
+       int offset;
+       unsigned val;
+       char *p;
+       FLAC__ASSERT(object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG)))
+               return false;
+       if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG)+4)
+               return false;
+       if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */
+               return false;
+       if(strncmp(p, "=0x", 3))
+               return false;
+       if(sscanf(p+3, "%x", &val) != 1)
+               return false;
+       *channel_mask = val;
+       return true;
+}
diff --git a/src/flac/utils.h b/src/flac/utils.h
new file mode 100644 (file)
index 0000000..74ab29e
--- /dev/null
@@ -0,0 +1,63 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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__utils_h
+#define flac__utils_h
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/ordinals.h"
+#include "FLAC/format.h" /* for FLAC__StreamMetadata_CueSheet */
+#include <stdio.h> /* for FILE */
+
+typedef struct {
+       FLAC__bool is_relative; /* i.e. specification string started with + or - */
+       FLAC__bool value_is_samples;
+       union {
+               double seconds;
+               FLAC__int64 samples;
+       } value;
+} utils__SkipUntilSpecification;
+
+typedef struct {
+       FLAC__bool has_start_point, has_end_point;
+       unsigned start_track, start_index;
+       unsigned end_track, end_index;
+} utils__CueSpecification;
+
+#ifdef FLAC__VALGRIND_TESTING
+size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+#else
+#define flac__utils_fwrite fwrite
+#endif
+
+extern int flac__utils_verbosity_;
+void flac__utils_printf(FILE *stream, int level, const char *format, ...);
+
+FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec);
+void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, unsigned sample_rate);
+
+FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec);
+void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec);
+
+FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask);
+FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask);
+
+#endif
diff --git a/src/flac/vorbiscomment.c b/src/flac/vorbiscomment.c
new file mode 100644 (file)
index 0000000..6b35a1e
--- /dev/null
@@ -0,0 +1,248 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "vorbiscomment.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h" /* for grabbag__file_get_filesize() */
+#include "share/utf8.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * This struct and the following 4 static functions are copied from
+ * ../metaflac/.  Maybe someday there will be a convenience
+ * library for Vorbis comment parsing.
+ */
+typedef struct {
+       char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */
+       char *field_name;
+       /* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
+       unsigned field_value_length;
+       char *field_value;
+       FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */
+} Argument_VcField;
+
+static void die(const char *message)
+{
+       FLAC__ASSERT(0 != message);
+       fprintf(stderr, "ERROR: %s\n", message);
+       exit(1);
+}
+
+static char *local_strdup(const char *source)
+{
+       char *ret;
+       FLAC__ASSERT(0 != source);
+       if(0 == (ret = strdup(source)))
+               die("out of memory during strdup()");
+       return ret;
+}
+
+static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation)
+{
+       static const char * const violations[] = {
+               "field name contains invalid character",
+               "field contains no '=' character"
+       };
+
+       char *p, *q, *s;
+
+       if(0 != field)
+               *field = local_strdup(field_ref);
+
+       s = local_strdup(field_ref);
+
+       if(0 == (p = strchr(s, '='))) {
+               free(s);
+               *violation = violations[1];
+               return false;
+       }
+       *p++ = '\0';
+
+       for(q = s; *q; q++) {
+               if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+                       free(s);
+                       *violation = violations[0];
+                       return false;
+               }
+       }
+
+       *name = local_strdup(s);
+       *value = local_strdup(p);
+       *length = strlen(p);
+
+       free(s);
+       return true;
+}
+
+/* slight modification: no 'filename' arg, and errors are passed back in 'violation' instead of printed to stderr */
+static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw, const char **violation)
+{
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+       char *converted;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != field);
+       FLAC__ASSERT(0 != needs_write);
+
+       if(field->field_value_from_file) {
+               /* read the file into 'data' */
+               FILE *f = 0;
+               char *data = 0;
+               const off_t size = grabbag__file_get_filesize(field->field_value);
+               if(size < 0) {
+                       *violation = "can't open file for tag value";
+                       return false;
+               }
+               if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */
+                       *violation = "file for tag value is too large";
+                       return false;
+               }
+               if(0 == (data = malloc(size+1)))
+                       die("out of memory allocating tag value");
+               data[size] = '\0';
+               if(0 == (f = fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) {
+                       free(data);
+                       if(f)
+                               fclose(f);
+                       *violation = "error while reading file for tag value";
+                       return false;
+               }
+               fclose(f);
+               if(strlen(data) != (size_t)size) {
+                       free(data);
+                       *violation = "file for tag value has embedded NULs";
+                       return false;
+               }
+
+               /* move 'data' into 'converted', converting to UTF-8 if necessary */
+               if(raw) {
+                       converted = data;
+               }
+               else if(utf8_encode(data, &converted) >= 0) {
+                       free(data);
+               }
+               else {
+                       free(data);
+                       *violation = "error converting file contents to UTF-8 for tag value";
+                       return false;
+               }
+
+               /* create and entry and append it */
+               if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) {
+                       free(converted);
+                       *violation = "file for tag value is not valid UTF-8";
+                       return false;
+               }
+               free(converted);
+               if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+                       *violation = "memory allocation failure";
+                       return false;
+               }
+
+               *needs_write = true;
+               return true;
+       }
+       else {
+               FLAC__bool needs_free = false;
+               if(raw) {
+                       entry.entry = (FLAC__byte *)field->field;
+               }
+               else if(utf8_encode(field->field, &converted) >= 0) {
+                       entry.entry = (FLAC__byte *)converted;
+                       needs_free = true;
+               }
+               else {
+                       *violation = "error converting comment to UTF-8";
+                       return false;
+               }
+               entry.length = strlen((const char *)entry.entry);
+               if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) {
+                       if(needs_free)
+                               free(converted);
+                       /*
+                        * our previous parsing has already established that the field
+                        * name is OK, so it must be the field value
+                        */
+                       *violation = "tag value for is not valid UTF-8";
+                       return false;
+               }
+
+               if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+                       if(needs_free)
+                               free(converted);
+                       *violation = "memory allocation failure";
+                       return false;
+               }
+
+               *needs_write = true;
+               if(needs_free)
+                       free(converted);
+               return true;
+       }
+}
+
+/*
+ * The rest of the code is novel
+ */
+
+static void free_field(Argument_VcField *obj)
+{
+       if(0 != obj->field)
+               free(obj->field);
+       if(0 != obj->field_name)
+               free(obj->field_name);
+       if(0 != obj->field_value)
+               free(obj->field_value);
+}
+
+FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation)
+{
+       Argument_VcField parsed;
+       FLAC__bool dummy;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != comment);
+
+       memset(&parsed, 0, sizeof(parsed));
+
+       parsed.field_value_from_file = value_from_file;
+       if(!parse_vorbis_comment_field(comment, &(parsed.field), &(parsed.field_name), &(parsed.field_value), &(parsed.field_value_length), violation)) {
+               free_field(&parsed);
+               return false;
+       }
+
+       if(!set_vc_field(block, &parsed, &dummy, raw, violation)) {
+               free_field(&parsed);
+               return false;
+       }
+       else {
+               free_field(&parsed);
+               return true;
+       }
+}
diff --git a/src/flac/vorbiscomment.h b/src/flac/vorbiscomment.h
new file mode 100644 (file)
index 0000000..1ff7006
--- /dev/null
@@ -0,0 +1,26 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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__vorbiscomment_h
+#define flac__vorbiscomment_h
+
+#include "FLAC/metadata.h"
+
+FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation);
+
+#endif
diff --git a/src/libFLAC++/Makefile.am b/src/libFLAC++/Makefile.am
new file mode 100644 (file)
index 0000000..360caa1
--- /dev/null
@@ -0,0 +1,55 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+lib_LTLIBRARIES = libFLAC++.la
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC++.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac++.pc
+
+EXTRA_DIST = \
+       Makefile.lite \
+       flac++.pc.in \
+       libFLAC++_dynamic.dsp \
+       libFLAC++_dynamic.vcproj \
+       libFLAC++_static.dsp \
+       libFLAC++_static.vcproj \
+       libFLAC++.m4
+
+# see 'http://www.gnu.org/software/libtool/manual.html#Libtool-versioning' for numbering convention
+libFLAC___la_LDFLAGS = -version-info 8:0:2
+libFLAC___la_LIBADD = ../libFLAC/libFLAC.la
+
+libFLAC___la_SOURCES = \
+       metadata.cpp \
+       stream_decoder.cpp \
+       stream_encoder.cpp
diff --git a/src/libFLAC++/Makefile.lite b/src/libFLAC++/Makefile.lite
new file mode 100644 (file)
index 0000000..ec1f678
--- /dev/null
@@ -0,0 +1,47 @@
+#  libFLAC++ - Free Lossless Audio Codec library
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+LIB_NAME = libFLAC++
+INCLUDES = -I$(topdir)/include
+
+SRCS_CPP = \
+       metadata.cpp \
+       stream_decoder.cpp \
+       stream_encoder.cpp
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/libFLAC++/flac++.pc.in b/src/libFLAC++/flac++.pc.in
new file mode 100644 (file)
index 0000000..f548311
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC++
+Description: Free Lossless Audio Codec Library (C++ API)
+Version: @VERSION@
+Requires: flac
+Libs: -L${libdir} -lFLAC++ -lm
+Cflags: -I${includedir}/FLAC++
diff --git a/src/libFLAC++/libFLAC++.m4 b/src/libFLAC++/libFLAC++.m4
new file mode 100644 (file)
index 0000000..bf37529
--- /dev/null
@@ -0,0 +1,117 @@
+# Configure paths for libFLAC++
+# "Inspired" by ogg.m4
+# Caller must first run AM_PATH_LIBFLAC
+
+dnl AM_PATH_LIBFLACPP([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libFLAC++, and define LIBFLACPP_CFLAGS, LIBFLACPP_LIBS, LIBFLACPP_LIBDIR
+dnl
+AC_DEFUN([AM_PATH_LIBFLACPP],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libFLACPP,[  --with-libFLACPP=PFX   Prefix where libFLAC++ is installed (optional)], libFLACPP_prefix="$withval", libFLACPP_prefix="")
+AC_ARG_WITH(libFLACPP-libraries,[  --with-libFLACPP-libraries=DIR   Directory where libFLAC++ library is installed (optional)], libFLACPP_libraries="$withval", libFLACPP_libraries="")
+AC_ARG_WITH(libFLACPP-includes,[  --with-libFLACPP-includes=DIR   Directory where libFLAC++ header files are installed (optional)], libFLACPP_includes="$withval", libFLACPP_includes="")
+AC_ARG_ENABLE(libFLACPPtest, [  --disable-libFLACPPtest       Do not try to compile and run a test libFLAC++ program],, enable_libFLACPPtest=yes)
+
+  if test "x$libFLACPP_libraries" != "x" ; then
+    LIBFLACPP_LIBDIR="$libFLACPP_libraries"
+  elif test "x$libFLACPP_prefix" != "x" ; then
+    LIBFLACPP_LIBDIR="$libFLACPP_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    LIBFLACPP_LIBDIR="$libdir"
+  fi
+
+  LIBFLACPP_LIBS="-L$LIBFLACPP_LIBDIR -lFLAC++ $LIBFLAC_LIBS"
+
+  if test "x$libFLACPP_includes" != "x" ; then
+    LIBFLACPP_CFLAGS="-I$libFLACPP_includes"
+  elif test "x$libFLACPP_prefix" != "x" ; then
+    LIBFLACPP_CFLAGS="-I$libFLACPP_prefix/include"
+  elif test "$prefix" != "xNONE"; then
+    LIBFLACPP_CFLAGS=""
+  fi
+
+  LIBFLACPP_CFLAGS="$LIBFLACPP_CFLAGS $LIBFLAC_CFLAGS"
+
+  AC_MSG_CHECKING(for libFLAC++)
+  no_libFLACPP=""
+
+
+  if test "x$enable_libFLACPPtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+    ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+    CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS"
+    CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS"
+    LIBS="$LIBS $LIBFLACPP_LIBS"
+    LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+dnl
+dnl Now check if the installed libFLAC++ is sufficiently new.
+dnl
+      rm -f conf.libFLAC++test
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC++/decoder.h>
+
+int main ()
+{
+  system("touch conf.libFLAC++test");
+  return 0;
+}
+
+],, no_libFLACPP=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+  fi
+
+  if test "x$no_libFLACPP" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.libFLAC++test ; then
+       :
+     else
+       echo "*** Could not run libFLAC++ test program, checking why..."
+       CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS"
+       CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS"
+       LIBS="$LIBS $LIBFLACPP_LIBS"
+       LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <FLAC++/decoder.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding libFLAC++ or finding the wrong"
+       echo "*** version of libFLAC++. If it is not finding libFLAC++, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means libFLAC++ was incorrectly installed"
+       echo "*** or that you have moved libFLAC++ since it was installed. In the latter case, you"
+       echo "*** may want to edit the libFLAC++-config script: $LIBFLACPP_CONFIG" ])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+     fi
+     LIBFLACPP_CFLAGS=""
+     LIBFLACPP_LIBDIR=""
+     LIBFLACPP_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(LIBFLACPP_CFLAGS)
+  AC_SUBST(LIBFLACPP_LIBDIR)
+  AC_SUBST(LIBFLACPP_LIBS)
+  rm -f conf.libFLAC++test
+])
diff --git a/src/libFLAC++/libFLAC++_dynamic.dsp b/src/libFLAC++/libFLAC++_dynamic.dsp
new file mode 100644 (file)
index 0000000..055d425
--- /dev/null
@@ -0,0 +1,139 @@
+# Microsoft Developer Studio Project File - Name="libFLAC++_dynamic" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=libFLAC++_dynamic - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC++_dynamic.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC++_dynamic.mak" CFG="libFLAC++_dynamic - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libFLAC++_dynamic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "libFLAC++_dynamic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "libFLAC++"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libFLAC++_dynamic - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_dynamic"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I ".\include" /I "..\..\include" /D "NDEBUG" /D "FLACPP_API_EXPORTS" /D "_WINDOWS" /D "_WINDLL" /D "WIN32" /D "_USRDLL" /FR /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG" /d "_USRDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\libFLAC.lib /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\obj\release\bin/libFLAC++.dll"\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC++_dynamic - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_dynamic"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I ".\include" /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLACPP_API_EXPORTS" /D "_WINDOWS" /D "_WINDLL" /D "WIN32" /D "_USRDLL" /FR /FD /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG" /d "_USRDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\libFLAC.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\..\obj\debug\bin/libFLAC++.dll" /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libFLAC++_dynamic - Win32 Release"\r
+# Name "libFLAC++_dynamic - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp"\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\all.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\decoder.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\encoder.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\export.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\metadata.h"\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/libFLAC++/libFLAC++_dynamic.vcproj b/src/libFLAC++/libFLAC++_dynamic.vcproj
new file mode 100644 (file)
index 0000000..e4cae62
--- /dev/null
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="libFLAC++_dynamic"\r
+       ProjectGUID="{4cefbc85-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="libFLAC++_dynamic"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLACPP_API_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\metadata.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_decoder.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\encoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\export.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\metadata.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/libFLAC++/libFLAC++_static.dsp b/src/libFLAC++/libFLAC++_static.dsp
new file mode 100644 (file)
index 0000000..c96eac1
--- /dev/null
@@ -0,0 +1,132 @@
+# Microsoft Developer Studio Project File - Name="libFLAC++_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=libFLAC++_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC++_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC++_static.mak" CFG="libFLAC++_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libFLAC++_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "libFLAC++_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "libFLAC++"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libFLAC++_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC++_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libFLAC++_static - Win32 Release"\r
+# Name "libFLAC++_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp"\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_decoder.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\all.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\decoder.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\encoder.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\export.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\include\FLAC++\metadata.h"\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/libFLAC++/libFLAC++_static.vcproj b/src/libFLAC++/libFLAC++_static.vcproj
new file mode 100644 (file)
index 0000000..f6df69e
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="libFLAC++_static"\r
+       ProjectGUID="{4cefbc86-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="libFLAC++_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\metadata.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_decoder.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\encoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\export.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC++\metadata.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/libFLAC++/metadata.cpp b/src/libFLAC++/metadata.cpp
new file mode 100644 (file)
index 0000000..7039624
--- /dev/null
@@ -0,0 +1,1589 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __STDC_LIMIT_MACROS 1 /* otherwise SIZE_MAX is not defined for c++ */
+#include "share/alloc.h"
+#include "FLAC++/metadata.h"
+#include "FLAC/assert.h"
+#include <stdlib.h> // for malloc(), free()
+#include <string.h> // for memcpy() etc.
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+       namespace Metadata {
+
+               // local utility routines
+
+               namespace local {
+
+                       Prototype *construct_block(::FLAC__StreamMetadata *object)
+                       {
+                               Prototype *ret = 0;
+                               switch(object->type) {
+                                       case FLAC__METADATA_TYPE_STREAMINFO:
+                                               ret = new StreamInfo(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_PADDING:
+                                               ret = new Padding(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_APPLICATION:
+                                               ret = new Application(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_SEEKTABLE:
+                                               ret = new SeekTable(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                                               ret = new VorbisComment(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_CUESHEET:
+                                               ret = new CueSheet(object, /*copy=*/false);
+                                               break;
+                                       case FLAC__METADATA_TYPE_PICTURE:
+                                               ret = new Picture(object, /*copy=*/false);
+                                               break;
+                                       default:
+                                               ret = new Unknown(object, /*copy=*/false);
+                                               break;
+                               }
+                               return ret;
+                       }
+
+               }
+
+               FLACPP_API Prototype *clone(const Prototype *object)
+               {
+                       FLAC__ASSERT(0 != object);
+
+                       const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
+                       const Padding *padding = dynamic_cast<const Padding *>(object);
+                       const Application *application = dynamic_cast<const Application *>(object);
+                       const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
+                       const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
+                       const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
+                       const Picture *picture = dynamic_cast<const Picture *>(object);
+                       const Unknown *unknown = dynamic_cast<const Unknown *>(object);
+
+                       if(0 != streaminfo)
+                               return new StreamInfo(*streaminfo);
+                       else if(0 != padding)
+                               return new Padding(*padding);
+                       else if(0 != application)
+                               return new Application(*application);
+                       else if(0 != seektable)
+                               return new SeekTable(*seektable);
+                       else if(0 != vorbiscomment)
+                               return new VorbisComment(*vorbiscomment);
+                       else if(0 != cuesheet)
+                               return new CueSheet(*cuesheet);
+                       else if(0 != picture)
+                               return new Picture(*picture);
+                       else if(0 != unknown)
+                               return new Unknown(*unknown);
+                       else {
+                               FLAC__ASSERT(0);
+                               return 0;
+                       }
+               }
+
+               //
+               // Prototype
+               //
+
+               Prototype::Prototype(const Prototype &object):
+               object_(::FLAC__metadata_object_clone(object.object_)),
+               is_reference_(false)
+               {
+                       FLAC__ASSERT(object.is_valid());
+               }
+
+               Prototype::Prototype(const ::FLAC__StreamMetadata &object):
+               object_(::FLAC__metadata_object_clone(&object)),
+               is_reference_(false)
+               {
+               }
+
+               Prototype::Prototype(const ::FLAC__StreamMetadata *object):
+               object_(::FLAC__metadata_object_clone(object)),
+               is_reference_(false)
+               {
+                       FLAC__ASSERT(0 != object);
+               }
+
+               Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy):
+               object_(copy? ::FLAC__metadata_object_clone(object) : object),
+               is_reference_(false)
+               {
+                       FLAC__ASSERT(0 != object);
+               }
+
+               Prototype::~Prototype()
+               {
+                       clear();
+               }
+
+               void Prototype::clear()
+               {
+                       if(0 != object_ && !is_reference_)
+                               FLAC__metadata_object_delete(object_);
+                       object_ = 0;
+               }
+
+               Prototype &Prototype::operator=(const Prototype &object)
+               {
+                       FLAC__ASSERT(object.is_valid());
+                       clear();
+                       is_reference_ = false;
+                       object_ = ::FLAC__metadata_object_clone(object.object_);
+                       return *this;
+               }
+
+               Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object)
+               {
+                       clear();
+                       is_reference_ = false;
+                       object_ = ::FLAC__metadata_object_clone(&object);
+                       return *this;
+               }
+
+               Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object)
+               {
+                       FLAC__ASSERT(0 != object);
+                       clear();
+                       is_reference_ = false;
+                       object_ = ::FLAC__metadata_object_clone(object);
+                       return *this;
+               }
+
+               Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy)
+               {
+                       FLAC__ASSERT(0 != object);
+                       clear();
+                       object_ = (copy? ::FLAC__metadata_object_clone(object) : object);
+                       is_reference_ = false;
+                       return *this;
+               }
+
+               bool Prototype::get_is_last() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)object_->is_last;
+               }
+
+               FLAC__MetadataType Prototype::get_type() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->type;
+               }
+
+               unsigned Prototype::get_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->length;
+               }
+
+               void Prototype::set_is_last(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->is_last = value;
+               }
+
+
+               //
+               // StreamInfo
+               //
+
+               StreamInfo::StreamInfo():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
+               { }
+
+               StreamInfo::~StreamInfo()
+               { }
+
+               unsigned StreamInfo::get_min_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.min_blocksize;
+               }
+
+               unsigned StreamInfo::get_max_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.max_blocksize;
+               }
+
+               unsigned StreamInfo::get_min_framesize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.min_framesize;
+               }
+
+               unsigned StreamInfo::get_max_framesize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.max_framesize;
+               }
+
+               unsigned StreamInfo::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.sample_rate;
+               }
+
+               unsigned StreamInfo::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.channels;
+               }
+
+               unsigned StreamInfo::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.bits_per_sample;
+               }
+
+               FLAC__uint64 StreamInfo::get_total_samples() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.total_samples;
+               }
+
+               const FLAC__byte *StreamInfo::get_md5sum() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.stream_info.md5sum;
+               }
+
+               void StreamInfo::set_min_blocksize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+                       FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+                       object_->data.stream_info.min_blocksize = value;
+               }
+
+               void StreamInfo::set_max_blocksize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+                       FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+                       object_->data.stream_info.max_blocksize = value;
+               }
+
+               void StreamInfo::set_min_framesize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+                       object_->data.stream_info.min_framesize = value;
+               }
+
+               void StreamInfo::set_max_framesize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+                       object_->data.stream_info.max_framesize = value;
+               }
+
+               void StreamInfo::set_sample_rate(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
+                       object_->data.stream_info.sample_rate = value;
+               }
+
+               void StreamInfo::set_channels(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value > 0);
+                       FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
+                       object_->data.stream_info.channels = value;
+               }
+
+               void StreamInfo::set_bits_per_sample(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
+                       FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
+                       object_->data.stream_info.bits_per_sample = value;
+               }
+
+               void StreamInfo::set_total_samples(FLAC__uint64 value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
+                       object_->data.stream_info.total_samples = value;
+               }
+
+               void StreamInfo::set_md5sum(const FLAC__byte value[16])
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != value);
+                       memcpy(object_->data.stream_info.md5sum, value, 16);
+               }
+
+
+               //
+               // Padding
+               //
+
+               Padding::Padding():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+               { }
+
+               Padding::~Padding()
+               { }
+
+               void Padding::set_length(unsigned length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->length = length;
+               }
+
+
+               //
+               // Application
+               //
+
+               Application::Application():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
+               { }
+
+               Application::~Application()
+               { }
+
+               const FLAC__byte *Application::get_id() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.application.id;
+               }
+
+               const FLAC__byte *Application::get_data() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.application.data;
+               }
+
+               void Application::set_id(const FLAC__byte value[4])
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != value);
+                       memcpy(object_->data.application.id, value, 4);
+               }
+
+               bool Application::set_data(const FLAC__byte *data, unsigned length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
+               }
+
+               bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
+               }
+
+
+               //
+               // SeekTable
+               //
+
+               SeekTable::SeekTable():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
+               { }
+
+               SeekTable::~SeekTable()
+               { }
+
+               unsigned SeekTable::get_num_points() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.seek_table.num_points;
+               }
+
+               ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.seek_table.num_points);
+                       return object_->data.seek_table.points[index];
+               }
+
+               void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.seek_table.num_points);
+                       ::FLAC__metadata_object_seektable_set_point(object_, index, point);
+               }
+
+               bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index <= object_->data.seek_table.num_points);
+                       return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
+               }
+
+               bool SeekTable::delete_point(unsigned index)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.seek_table.num_points);
+                       return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
+               }
+
+               bool SeekTable::is_legal() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
+               }
+
+
+               //
+               // VorbisComment::Entry
+               //
+
+               VorbisComment::Entry::Entry()
+               {
+                       zero();
+               }
+
+               VorbisComment::Entry::Entry(const char *field, unsigned field_length)
+               {
+                       zero();
+                       construct(field, field_length);
+               }
+
+               VorbisComment::Entry::Entry(const char *field)
+               {
+                       zero();
+                       construct(field);
+               }
+
+               VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
+               {
+                       zero();
+                       construct(field_name, field_value, field_value_length);
+               }
+
+               VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
+               {
+                       zero();
+                       construct(field_name, field_value);
+               }
+
+               VorbisComment::Entry::Entry(const Entry &entry)
+               {
+                       FLAC__ASSERT(entry.is_valid());
+                       zero();
+                       construct((const char *)entry.entry_.entry, entry.entry_.length);
+               }
+
+               VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
+               {
+                       FLAC__ASSERT(entry.is_valid());
+                       clear();
+                       construct((const char *)entry.entry_.entry, entry.entry_.length);
+                       return *this;
+               }
+
+               VorbisComment::Entry::~Entry()
+               {
+                       clear();
+               }
+
+               bool VorbisComment::Entry::is_valid() const
+               {
+                       return is_valid_;
+               }
+
+               unsigned VorbisComment::Entry::get_field_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return entry_.length;
+               }
+
+               unsigned VorbisComment::Entry::get_field_name_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return field_name_length_;
+               }
+
+               unsigned VorbisComment::Entry::get_field_value_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return field_value_length_;
+               }
+
+               ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return entry_;
+               }
+
+               const char *VorbisComment::Entry::get_field() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (const char *)entry_.entry;
+               }
+
+               const char *VorbisComment::Entry::get_field_name() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return field_name_;
+               }
+
+               const char *VorbisComment::Entry::get_field_value() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return field_value_;
+               }
+
+               bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != field);
+
+                       if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length))
+                               return is_valid_ = false;
+
+                       clear_entry();
+
+                       if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_2op_(field_length, /*+*/1))) {
+                               is_valid_ = false;
+                       }
+                       else {
+                               entry_.length = field_length;
+                               memcpy(entry_.entry, field, field_length);
+                               entry_.entry[field_length] = '\0';
+                               (void) parse_field();
+                       }
+
+                       return is_valid_;
+               }
+
+               bool VorbisComment::Entry::set_field(const char *field)
+               {
+                       return set_field(field, strlen(field));
+               }
+
+               bool VorbisComment::Entry::set_field_name(const char *field_name)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != field_name);
+
+                       if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+                               return is_valid_ = false;
+
+                       clear_field_name();
+
+                       if(0 == (field_name_ = strdup(field_name))) {
+                               is_valid_ = false;
+                       }
+                       else {
+                               field_name_length_ = strlen(field_name_);
+                               compose_field();
+                       }
+
+                       return is_valid_;
+               }
+
+               bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != field_value);
+
+                       if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length))
+                               return is_valid_ = false;
+
+                       clear_field_value();
+
+                       if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length, /*+*/1))) {
+                               is_valid_ = false;
+                       }
+                       else {
+                               field_value_length_ = field_value_length;
+                               memcpy(field_value_, field_value, field_value_length);
+                               field_value_[field_value_length] = '\0';
+                               compose_field();
+                       }
+
+                       return is_valid_;
+               }
+
+               bool VorbisComment::Entry::set_field_value(const char *field_value)
+               {
+                       return set_field_value(field_value, strlen(field_value));
+               }
+
+               void VorbisComment::Entry::zero()
+               {
+                       is_valid_ = true;
+                       entry_.length = 0;
+                       entry_.entry = 0;
+                       field_name_ = 0;
+                       field_name_length_ = 0;
+                       field_value_ = 0;
+                       field_value_length_ = 0;
+               }
+
+               void VorbisComment::Entry::clear()
+               {
+                       clear_entry();
+                       clear_field_name();
+                       clear_field_value();
+                       is_valid_ = true;
+               }
+
+               void VorbisComment::Entry::clear_entry()
+               {
+                       if(0 != entry_.entry) {
+                               free(entry_.entry);
+                               entry_.entry = 0;
+                               entry_.length = 0;
+                       }
+               }
+
+               void VorbisComment::Entry::clear_field_name()
+               {
+                       if(0 != field_name_) {
+                               free(field_name_);
+                               field_name_ = 0;
+                               field_name_length_ = 0;
+                       }
+               }
+
+               void VorbisComment::Entry::clear_field_value()
+               {
+                       if(0 != field_value_) {
+                               free(field_value_);
+                               field_value_ = 0;
+                               field_value_length_ = 0;
+                       }
+               }
+
+               void VorbisComment::Entry::construct(const char *field, unsigned field_length)
+               {
+                       if(set_field(field, field_length))
+                               parse_field();
+               }
+
+               void VorbisComment::Entry::construct(const char *field)
+               {
+                       construct(field, strlen(field));
+               }
+
+               void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
+               {
+                       if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
+                               compose_field();
+               }
+
+               void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
+               {
+                       construct(field_name, field_value, strlen(field_value));
+               }
+
+               void VorbisComment::Entry::compose_field()
+               {
+                       clear_entry();
+
+                       if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1))) {
+                               is_valid_ = false;
+                       }
+                       else {
+                               memcpy(entry_.entry, field_name_, field_name_length_);
+                               entry_.length += field_name_length_;
+                               memcpy(entry_.entry + entry_.length, "=", 1);
+                               entry_.length += 1;
+                               memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
+                               entry_.length += field_value_length_;
+                               entry_.entry[entry_.length] = '\0';
+                               is_valid_ = true;
+                       }
+               }
+
+               void VorbisComment::Entry::parse_field()
+               {
+                       clear_field_name();
+                       clear_field_value();
+
+                       const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
+
+                       if(0 == p)
+                               p = (const char *)entry_.entry + entry_.length;
+
+                       field_name_length_ = (unsigned)(p - (const char *)entry_.entry);
+                       if(0 == (field_name_ = (char *)safe_malloc_add_2op_(field_name_length_, /*+*/1))) { // +1 for the trailing \0
+                               is_valid_ = false;
+                               return;
+                       }
+                       memcpy(field_name_, entry_.entry, field_name_length_);
+                       field_name_[field_name_length_] = '\0';
+
+                       if(entry_.length - field_name_length_ == 0) {
+                               field_value_length_ = 0;
+                               if(0 == (field_value_ = (char *)safe_malloc_(0))) {
+                                       is_valid_ = false;
+                                       return;
+                               }
+                       }
+                       else {
+                               field_value_length_ = entry_.length - field_name_length_ - 1;
+                               if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length_, /*+*/1))) { // +1 for the trailing \0
+                                       is_valid_ = false;
+                                       return;
+                               }
+                               memcpy(field_value_, ++p, field_value_length_);
+                               field_value_[field_value_length_] = '\0';
+                       }
+
+                       is_valid_ = true;
+               }
+
+
+               //
+               // VorbisComment
+               //
+
+               VorbisComment::VorbisComment():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
+               { }
+
+               VorbisComment::~VorbisComment()
+               { }
+
+               unsigned VorbisComment::get_num_comments() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.vorbis_comment.num_comments;
+               }
+
+               const FLAC__byte *VorbisComment::get_vendor_string() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.vorbis_comment.vendor_string.entry;
+               }
+
+               VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+                       return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
+               }
+
+               bool VorbisComment::set_vendor_string(const FLAC__byte *string)
+               {
+                       FLAC__ASSERT(is_valid());
+                       // vendor_string is a special kind of entry
+                       const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { strlen((const char *)string), (FLAC__byte*)string }; // we can cheat on const-ness because we make a copy below:
+                       return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
+               }
+
+               bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+                       return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
+               }
+
+               bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
+                       return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
+               }
+
+               bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
+               }
+
+               bool VorbisComment::delete_comment(unsigned index)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+                       return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
+               }
+
+
+               //
+               // CueSheet::Track
+               //
+
+               CueSheet::Track::Track():
+               object_(::FLAC__metadata_object_cuesheet_track_new())
+               { }
+
+               CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track):
+               object_(::FLAC__metadata_object_cuesheet_track_clone(track))
+               { }
+
+               CueSheet::Track::Track(const Track &track):
+               object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_))
+               { }
+
+               CueSheet::Track &CueSheet::Track::operator=(const Track &track)
+               {
+                       if(0 != object_)
+                               ::FLAC__metadata_object_cuesheet_track_delete(object_);
+                       object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_);
+                       return *this;
+               }
+
+               CueSheet::Track::~Track()
+               {
+                       if(0 != object_)
+                               ::FLAC__metadata_object_cuesheet_track_delete(object_);
+               }
+
+               bool CueSheet::Track::is_valid() const
+               {
+                       return(0 != object_);
+               }
+
+               ::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(unsigned i) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i < object_->num_indices);
+                       return object_->indices[i];
+               }
+
+               void CueSheet::Track::set_isrc(const char value[12])
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != value);
+                       memcpy(object_->isrc, value, 12);
+                       object_->isrc[12] = '\0';
+               }
+
+               void CueSheet::Track::set_type(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(value <= 1);
+                       object_->type = value;
+               }
+
+               void CueSheet::Track::set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i < object_->num_indices);
+                       object_->indices[i] = index;
+               }
+
+
+               //
+               // CueSheet
+               //
+
+               CueSheet::CueSheet():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false)
+               { }
+
+               CueSheet::~CueSheet()
+               { }
+
+               const char *CueSheet::get_media_catalog_number() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.cue_sheet.media_catalog_number;
+               }
+
+               FLAC__uint64 CueSheet::get_lead_in() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.cue_sheet.lead_in;
+               }
+
+               bool CueSheet::get_is_cd() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.cue_sheet.is_cd? true : false;
+               }
+
+               unsigned CueSheet::get_num_tracks() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.cue_sheet.num_tracks;
+               }
+
+               CueSheet::Track CueSheet::get_track(unsigned i) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+                       return Track(object_->data.cue_sheet.tracks + i);
+               }
+
+               void CueSheet::set_media_catalog_number(const char value[128])
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(0 != value);
+                       memcpy(object_->data.cue_sheet.media_catalog_number, value, 128);
+                       object_->data.cue_sheet.media_catalog_number[128] = '\0';
+               }
+
+               void CueSheet::set_lead_in(FLAC__uint64 value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.cue_sheet.lead_in = value;
+               }
+
+               void CueSheet::set_is_cd(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.cue_sheet.is_cd = value;
+               }
+
+               void CueSheet::set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+                       FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
+                       object_->data.cue_sheet.tracks[track_num].indices[index_num] = index;
+               }
+
+               bool CueSheet::insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+                       FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices);
+                       return (bool)::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, index);
+               }
+
+               bool CueSheet::delete_index(unsigned track_num, unsigned index_num)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+                       FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices);
+                       return (bool)::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num);
+               }
+
+               bool CueSheet::set_track(unsigned i, const CueSheet::Track &track)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+                       // We can safely const_cast since copy=true
+                       return (bool)::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
+               }
+
+               bool CueSheet::insert_track(unsigned i, const CueSheet::Track &track)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
+                       // We can safely const_cast since copy=true
+                       return (bool)::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
+               }
+
+               bool CueSheet::delete_track(unsigned i)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+                       return (bool)::FLAC__metadata_object_cuesheet_delete_track(object_, i);
+               }
+
+               bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
+               }
+
+               FLAC__uint32 CueSheet::calculate_cddb_id() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
+               }
+
+
+               //
+               // Picture
+               //
+
+               Picture::Picture():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
+               { }
+
+               Picture::~Picture()
+               { }
+
+               ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.type;
+               }
+
+               const char *Picture::get_mime_type() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.mime_type;
+               }
+
+               const FLAC__byte *Picture::get_description() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.description;
+               }
+
+               FLAC__uint32 Picture::get_width() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.width;
+               }
+
+               FLAC__uint32 Picture::get_height() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.height;
+               }
+
+               FLAC__uint32 Picture::get_depth() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.depth;
+               }
+
+               FLAC__uint32 Picture::get_colors() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.colors;
+               }
+
+               FLAC__uint32 Picture::get_data_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.data_length;
+               }
+
+               const FLAC__byte *Picture::get_data() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.picture.data;
+               }
+
+               void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.picture.type = type;
+               }
+
+               bool Picture::set_mime_type(const char *string)
+               {
+                       FLAC__ASSERT(is_valid());
+                       // We can safely const_cast since copy=true
+                       return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
+               }
+
+               bool Picture::set_description(const FLAC__byte *string)
+               {
+                       FLAC__ASSERT(is_valid());
+                       // We can safely const_cast since copy=true
+                       return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
+               }
+
+               void Picture::set_width(FLAC__uint32 value) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.picture.width = value;
+               }
+
+               void Picture::set_height(FLAC__uint32 value) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.picture.height = value;
+               }
+
+               void Picture::set_depth(FLAC__uint32 value) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.picture.depth = value;
+               }
+
+               void Picture::set_colors(FLAC__uint32 value) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       object_->data.picture.colors = value;
+               }
+
+               bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       // We can safely const_cast since copy=true
+                       return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
+               }
+
+
+               //
+               // Unknown
+               //
+
+               Unknown::Unknown():
+               Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
+               { }
+
+               Unknown::~Unknown()
+               { }
+
+               const FLAC__byte *Unknown::get_data() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return object_->data.application.data;
+               }
+
+               bool Unknown::set_data(const FLAC__byte *data, unsigned length)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
+               }
+
+               bool Unknown::set_data(FLAC__byte *data, unsigned length, bool copy)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
+               }
+
+
+               // ============================================================
+               //
+               //  Level 0
+               //
+               // ============================================================
+
+               FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata object;
+
+                       if(::FLAC__metadata_get_streaminfo(filename, &object)) {
+                               streaminfo = object;
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       tags = 0;
+
+                       if(::FLAC__metadata_get_tags(filename, &object)) {
+                               tags = new VorbisComment(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_tags(const char *filename, VorbisComment &tags)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       if(::FLAC__metadata_get_tags(filename, &object)) {
+                               tags.assign(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       cuesheet = 0;
+
+                       if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+                               cuesheet = new CueSheet(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+                               cuesheet.assign(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       picture = 0;
+
+                       if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
+                               picture = new Picture(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) {
+                               picture.assign(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+
+               // ============================================================
+               //
+               //  Level 1
+               //
+               // ============================================================
+
+               SimpleIterator::SimpleIterator():
+               iterator_(::FLAC__metadata_simple_iterator_new())
+               { }
+
+               SimpleIterator::~SimpleIterator()
+               {
+                       clear();
+               }
+
+               void SimpleIterator::clear()
+               {
+                       if(0 != iterator_)
+                               FLAC__metadata_simple_iterator_delete(iterator_);
+                       iterator_ = 0;
+               }
+
+               bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats)
+               {
+                       FLAC__ASSERT(0 != filename);
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
+               }
+
+               bool SimpleIterator::is_valid() const
+               {
+                       return 0 != iterator_;
+               }
+
+               SimpleIterator::Status SimpleIterator::status()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return Status(::FLAC__metadata_simple_iterator_status(iterator_));
+               }
+
+               bool SimpleIterator::is_writable() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
+               }
+
+               bool SimpleIterator::next()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
+               }
+
+               bool SimpleIterator::prev()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
+               }
+
+               //@@@@ add to tests
+               bool SimpleIterator::is_last() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_is_last(iterator_);
+               }
+
+               //@@@@ add to tests
+               off_t SimpleIterator::get_block_offset() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
+               }
+
+               ::FLAC__MetadataType SimpleIterator::get_block_type() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
+               }
+
+               //@@@@ add to tests
+               unsigned SimpleIterator::get_block_length() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
+               }
+
+               //@@@@ add to tests
+               bool SimpleIterator::get_application_id(FLAC__byte *id)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
+               }
+
+               Prototype *SimpleIterator::get_block()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
+               }
+
+               bool SimpleIterator::set_block(Prototype *block, bool use_padding)
+               {
+                       FLAC__ASSERT(0 != block);
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
+               }
+
+               bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
+               {
+                       FLAC__ASSERT(0 != block);
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
+               }
+
+               bool SimpleIterator::delete_block(bool use_padding)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
+               }
+
+
+               // ============================================================
+               //
+               //  Level 2
+               //
+               // ============================================================
+
+               Chain::Chain():
+               chain_(::FLAC__metadata_chain_new())
+               { }
+
+               Chain::~Chain()
+               {
+                       clear();
+               }
+
+               void Chain::clear()
+               {
+                       if(0 != chain_)
+                               FLAC__metadata_chain_delete(chain_);
+                       chain_ = 0;
+               }
+
+               bool Chain::is_valid() const
+               {
+                       return 0 != chain_;
+               }
+
+               Chain::Status Chain::status()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return Status(::FLAC__metadata_chain_status(chain_));
+               }
+
+               bool Chain::read(const char *filename, bool is_ogg)
+               {
+                       FLAC__ASSERT(0 != filename);
+                       FLAC__ASSERT(is_valid());
+                       return is_ogg?
+                               (bool)::FLAC__metadata_chain_read_ogg(chain_, filename) :
+                               (bool)::FLAC__metadata_chain_read(chain_, filename)
+                       ;
+               }
+
+               bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return is_ogg?
+                               (bool)::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks) :
+                               (bool)::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)
+                       ;
+               }
+
+               bool Chain::check_if_tempfile_needed(bool use_padding)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
+               }
+
+               bool Chain::write(bool use_padding, bool preserve_file_stats)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
+               }
+
+               bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
+               }
+
+               bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
+               }
+
+               void Chain::merge_padding()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::FLAC__metadata_chain_merge_padding(chain_);
+               }
+
+               void Chain::sort_padding()
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::FLAC__metadata_chain_sort_padding(chain_);
+               }
+
+
+               Iterator::Iterator():
+               iterator_(::FLAC__metadata_iterator_new())
+               { }
+
+               Iterator::~Iterator()
+               {
+                       clear();
+               }
+
+               void Iterator::clear()
+               {
+                       if(0 != iterator_)
+                               FLAC__metadata_iterator_delete(iterator_);
+                       iterator_ = 0;
+               }
+
+               bool Iterator::is_valid() const
+               {
+                       return 0 != iterator_;
+               }
+
+               void Iterator::init(Chain &chain)
+               {
+                       FLAC__ASSERT(is_valid());
+                       FLAC__ASSERT(chain.is_valid());
+                       ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
+               }
+
+               bool Iterator::next()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_iterator_next(iterator_);
+               }
+
+               bool Iterator::prev()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_iterator_prev(iterator_);
+               }
+
+               ::FLAC__MetadataType Iterator::get_block_type() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_iterator_get_block_type(iterator_);
+               }
+
+               Prototype *Iterator::get_block()
+               {
+                       FLAC__ASSERT(is_valid());
+                       Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
+                       if(0 != block)
+                               block->set_reference(true);
+                       return block;
+               }
+
+               bool Iterator::set_block(Prototype *block)
+               {
+                       FLAC__ASSERT(0 != block);
+                       FLAC__ASSERT(is_valid());
+                       bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
+                       if(ret) {
+                               block->set_reference(true);
+                               delete block;
+                       }
+                       return ret;
+               }
+
+               bool Iterator::delete_block(bool replace_with_padding)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
+               }
+
+               bool Iterator::insert_block_before(Prototype *block)
+               {
+                       FLAC__ASSERT(0 != block);
+                       FLAC__ASSERT(is_valid());
+                       bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
+                       if(ret) {
+                               block->set_reference(true);
+                               delete block;
+                       }
+                       return ret;
+               }
+
+               bool Iterator::insert_block_after(Prototype *block)
+               {
+                       FLAC__ASSERT(0 != block);
+                       FLAC__ASSERT(is_valid());
+                       bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
+                       if(ret) {
+                               block->set_reference(true);
+                               delete block;
+                       }
+                       return ret;
+               }
+
+       }
+}
diff --git a/src/libFLAC++/stream_decoder.cpp b/src/libFLAC++/stream_decoder.cpp
new file mode 100644 (file)
index 0000000..fee69ba
--- /dev/null
@@ -0,0 +1,389 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FLAC++/decoder.h"
+#include "FLAC/assert.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+       namespace Decoder {
+
+               // ------------------------------------------------------------
+               //
+               // Stream
+               //
+               // ------------------------------------------------------------
+
+               Stream::Stream():
+               decoder_(::FLAC__stream_decoder_new())
+               { }
+
+               Stream::~Stream()
+               {
+                       if(0 != decoder_) {
+                               (void)::FLAC__stream_decoder_finish(decoder_);
+                               ::FLAC__stream_decoder_delete(decoder_);
+                       }
+               }
+
+               bool Stream::is_valid() const
+               {
+                       return 0 != decoder_;
+               }
+
+               bool Stream::set_ogg_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_ogg_serial_number(decoder_, value);
+               }
+
+               bool Stream::set_md5_checking(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_md5_checking(decoder_, value);
+               }
+
+               bool Stream::set_metadata_respond(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_respond(decoder_, type);
+               }
+
+               bool Stream::set_metadata_respond_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_respond_application(decoder_, id);
+               }
+
+               bool Stream::set_metadata_respond_all()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_respond_all(decoder_);
+               }
+
+               bool Stream::set_metadata_ignore(::FLAC__MetadataType type)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_ignore(decoder_, type);
+               }
+
+               bool Stream::set_metadata_ignore_application(const FLAC__byte id[4])
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_ignore_application(decoder_, id);
+               }
+
+               bool Stream::set_metadata_ignore_all()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_set_metadata_ignore_all(decoder_);
+               }
+
+               Stream::State Stream::get_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return State(::FLAC__stream_decoder_get_state(decoder_));
+               }
+
+               bool Stream::get_md5_checking() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_get_md5_checking(decoder_);
+               }
+
+               FLAC__uint64 Stream::get_total_samples() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_total_samples(decoder_);
+               }
+
+               unsigned Stream::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_channels(decoder_);
+               }
+
+               ::FLAC__ChannelAssignment Stream::get_channel_assignment() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_channel_assignment(decoder_);
+               }
+
+               unsigned Stream::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_bits_per_sample(decoder_);
+               }
+
+               unsigned Stream::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_sample_rate(decoder_);
+               }
+
+               unsigned Stream::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_blocksize(decoder_);
+               }
+
+               bool Stream::get_decode_position(FLAC__uint64 *position) const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_get_decode_position(decoder_, position);
+               }
+
+               ::FLAC__StreamDecoderInitStatus Stream::init()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_init_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamDecoderInitStatus Stream::init_ogg()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_decoder_init_ogg_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               bool Stream::finish()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_finish(decoder_);
+               }
+
+               bool Stream::flush()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_flush(decoder_);
+               }
+
+               bool Stream::reset()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_reset(decoder_);
+               }
+
+               bool Stream::process_single()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_process_single(decoder_);
+               }
+
+               bool Stream::process_until_end_of_metadata()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_process_until_end_of_metadata(decoder_);
+               }
+
+               bool Stream::process_until_end_of_stream()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_process_until_end_of_stream(decoder_);
+               }
+
+               bool Stream::skip_single_frame()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_skip_single_frame(decoder_);
+               }
+
+               bool Stream::seek_absolute(FLAC__uint64 sample)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_seek_absolute(decoder_, sample);
+               }
+
+               ::FLAC__StreamDecoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset)
+               {
+                       (void)absolute_byte_offset;
+                       return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+               }
+
+               ::FLAC__StreamDecoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset)
+               {
+                       (void)absolute_byte_offset;
+                       return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+               }
+
+               ::FLAC__StreamDecoderLengthStatus Stream::length_callback(FLAC__uint64 *stream_length)
+               {
+                       (void)stream_length;
+                       return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+               }
+
+               bool Stream::eof_callback()
+               {
+                       return false;
+               }
+
+               void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+               {
+                       (void)metadata;
+               }
+
+               ::FLAC__StreamDecoderReadStatus Stream::read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+               {
+                       (void)decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->read_callback(buffer, bytes);
+               }
+
+               ::FLAC__StreamDecoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->seek_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__StreamDecoderTellStatus Stream::tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->tell_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__StreamDecoderLengthStatus Stream::length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->length_callback(stream_length);
+               }
+
+               FLAC__bool Stream::eof_callback_(const ::FLAC__StreamDecoder *decoder, void *client_data)
+               {
+                       (void) decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->eof_callback();
+               }
+
+               ::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);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->write_callback(frame, buffer);
+               }
+
+               void Stream::metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+               {
+                       (void)decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->metadata_callback(metadata);
+               }
+
+               void Stream::error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data)
+               {
+                       (void)decoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->error_callback(status);
+               }
+
+               // ------------------------------------------------------------
+               //
+               // File
+               //
+               // ------------------------------------------------------------
+
+               File::File():
+                       Stream()
+               { }
+
+               File::~File()
+               {
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init(FILE *file)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return ::FLAC__stream_decoder_init_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init(const char *filename)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return ::FLAC__stream_decoder_init_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init(const std::string &filename)
+               {
+                       return init(filename.c_str());
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init_ogg(FILE *file)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return ::FLAC__stream_decoder_init_ogg_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init_ogg(const char *filename)
+               {
+                       FLAC__ASSERT(0 != decoder_);
+                       return ::FLAC__stream_decoder_init_ogg_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamDecoderInitStatus File::init_ogg(const std::string &filename)
+               {
+                       return init_ogg(filename.c_str());
+               }
+
+               // This is a dummy to satisfy the pure virtual from Stream; the
+               // read callback will never be called since we are initializing
+               // with FLAC__stream_decoder_init_FILE() or
+               // FLAC__stream_decoder_init_file() and those supply the read
+               // callback internally.
+               ::FLAC__StreamDecoderReadStatus File::read_callback(FLAC__byte buffer[], size_t *bytes)
+               {
+                       (void)buffer, (void)bytes;
+                       FLAC__ASSERT(false);
+                       return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; // double protection
+               }
+
+       }
+}
diff --git a/src/libFLAC++/stream_encoder.cpp b/src/libFLAC++/stream_encoder.cpp
new file mode 100644 (file)
index 0000000..cf65f23
--- /dev/null
@@ -0,0 +1,511 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FLAC++/encoder.h"
+#include "FLAC++/metadata.h"
+#include "FLAC/assert.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+namespace FLAC {
+       namespace Encoder {
+
+               // ------------------------------------------------------------
+               //
+               // Stream
+               //
+               // ------------------------------------------------------------
+
+               Stream::Stream():
+               encoder_(::FLAC__stream_encoder_new())
+               { }
+
+               Stream::~Stream()
+               {
+                       if(0 != encoder_) {
+                               (void)::FLAC__stream_encoder_finish(encoder_);
+                               ::FLAC__stream_encoder_delete(encoder_);
+                       }
+               }
+
+               bool Stream::is_valid() const
+               {
+                       return 0 != encoder_;
+               }
+
+               bool Stream::set_ogg_serial_number(long value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_ogg_serial_number(encoder_, value);
+               }
+
+               bool Stream::set_verify(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_verify(encoder_, value);
+               }
+
+               bool Stream::set_streamable_subset(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_streamable_subset(encoder_, value);
+               }
+
+               bool Stream::set_channels(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_channels(encoder_, value);
+               }
+
+               bool Stream::set_bits_per_sample(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_bits_per_sample(encoder_, value);
+               }
+
+               bool Stream::set_sample_rate(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_sample_rate(encoder_, value);
+               }
+
+               bool Stream::set_compression_level(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_compression_level(encoder_, value);
+               }
+
+               bool Stream::set_blocksize(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_blocksize(encoder_, value);
+               }
+
+               bool Stream::set_do_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_do_mid_side_stereo(encoder_, value);
+               }
+
+               bool Stream::set_loose_mid_side_stereo(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_, value);
+               }
+
+               bool Stream::set_apodization(const char *specification)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_apodization(encoder_, specification);
+               }
+
+               bool Stream::set_max_lpc_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_max_lpc_order(encoder_, value);
+               }
+
+               bool Stream::set_qlp_coeff_precision(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_qlp_coeff_precision(encoder_, value);
+               }
+
+               bool Stream::set_do_qlp_coeff_prec_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_, value);
+               }
+
+               bool Stream::set_do_escape_coding(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_do_escape_coding(encoder_, value);
+               }
+
+               bool Stream::set_do_exhaustive_model_search(bool value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_, value);
+               }
+
+               bool Stream::set_min_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_min_residual_partition_order(encoder_, value);
+               }
+
+               bool Stream::set_max_residual_partition_order(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_max_residual_partition_order(encoder_, value);
+               }
+
+               bool Stream::set_rice_parameter_search_dist(unsigned value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_, value);
+               }
+
+               bool Stream::set_total_samples_estimate(FLAC__uint64 value)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value);
+               }
+
+               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);
+               }
+
+               bool Stream::set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks)
+               {
+                       FLAC__ASSERT(is_valid());
+#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __SUNPRO_CC)
+                       // MSVC++ can't handle:
+                       // ::FLAC__StreamMetadata *m[num_blocks];
+                       // so we do this ugly workaround
+                       ::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks];
+#else
+                       ::FLAC__StreamMetadata *m[num_blocks];
+#endif
+                       for(unsigned i = 0; i < num_blocks; i++) {
+                               // we can get away with the const_cast since we know the encoder will only correct the is_last flags
+                               m[i] = const_cast< ::FLAC__StreamMetadata*>((const ::FLAC__StreamMetadata*)metadata[i]);
+                       }
+#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __SUNPRO_CC)
+                       // complete the hack
+                       const bool ok = (bool)::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks);
+                       delete [] m;
+                       return ok;
+#else
+                       return (bool)::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks);
+#endif
+               }
+
+               Stream::State Stream::get_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return State(::FLAC__stream_encoder_get_state(encoder_));
+               }
+
+               Decoder::Stream::State Stream::get_verify_decoder_state() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return Decoder::Stream::State(::FLAC__stream_encoder_get_verify_decoder_state(encoder_));
+               }
+
+               void Stream::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+               {
+                       FLAC__ASSERT(is_valid());
+                       ::FLAC__stream_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got);
+               }
+
+               bool Stream::get_verify() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_verify(encoder_);
+               }
+
+               bool Stream::get_streamable_subset() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_streamable_subset(encoder_);
+               }
+
+               bool Stream::get_do_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_do_mid_side_stereo(encoder_);
+               }
+
+               bool Stream::get_loose_mid_side_stereo() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_loose_mid_side_stereo(encoder_);
+               }
+
+               unsigned Stream::get_channels() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_channels(encoder_);
+               }
+
+               unsigned Stream::get_bits_per_sample() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_bits_per_sample(encoder_);
+               }
+
+               unsigned Stream::get_sample_rate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_sample_rate(encoder_);
+               }
+
+               unsigned Stream::get_blocksize() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_blocksize(encoder_);
+               }
+
+               unsigned Stream::get_max_lpc_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_max_lpc_order(encoder_);
+               }
+
+               unsigned Stream::get_qlp_coeff_precision() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_qlp_coeff_precision(encoder_);
+               }
+
+               bool Stream::get_do_qlp_coeff_prec_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder_);
+               }
+
+               bool Stream::get_do_escape_coding() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_do_escape_coding(encoder_);
+               }
+
+               bool Stream::get_do_exhaustive_model_search() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_get_do_exhaustive_model_search(encoder_);
+               }
+
+               unsigned Stream::get_min_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_min_residual_partition_order(encoder_);
+               }
+
+               unsigned Stream::get_max_residual_partition_order() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_max_residual_partition_order(encoder_);
+               }
+
+               unsigned Stream::get_rice_parameter_search_dist() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_rice_parameter_search_dist(encoder_);
+               }
+
+               FLAC__uint64 Stream::get_total_samples_estimate() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_get_total_samples_estimate(encoder_);
+               }
+
+               ::FLAC__StreamEncoderInitStatus Stream::init()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_stream(encoder_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamEncoderInitStatus Stream::init_ogg()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_ogg_stream(encoder_, read_callback_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
+               }
+
+               bool Stream::finish()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_finish(encoder_);
+               }
+
+               bool Stream::process(const FLAC__int32 * const buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_process(encoder_, buffer, samples);
+               }
+
+               bool Stream::process_interleaved(const FLAC__int32 buffer[], unsigned samples)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_encoder_process_interleaved(encoder_, buffer, samples);
+               }
+
+               ::FLAC__StreamEncoderReadStatus Stream::read_callback(FLAC__byte buffer[], size_t *bytes)
+               {
+                       (void)buffer, (void)bytes;
+                       return ::FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED;
+               }
+
+               ::FLAC__StreamEncoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset)
+               {
+                       (void)absolute_byte_offset;
+                       return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+               }
+
+               ::FLAC__StreamEncoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset)
+               {
+                       (void)absolute_byte_offset;
+                       return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+               }
+
+               void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+               {
+                       (void)metadata;
+               }
+
+               ::FLAC__StreamEncoderReadStatus Stream::read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->read_callback(buffer, bytes);
+               }
+
+               ::FLAC__StreamEncoderWriteStatus Stream::write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->write_callback(buffer, bytes, samples, current_frame);
+               }
+
+               ::FLAC__StreamEncoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->seek_callback(absolute_byte_offset);
+               }
+
+               ::FLAC__StreamEncoderTellStatus Stream::tell_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       return instance->tell_callback(absolute_byte_offset);
+               }
+
+               void Stream::metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       Stream *instance = reinterpret_cast<Stream *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->metadata_callback(metadata);
+               }
+
+               // ------------------------------------------------------------
+               //
+               // File
+               //
+               // ------------------------------------------------------------
+
+               File::File():
+                       Stream()
+               { }
+
+               File::~File()
+               {
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init(FILE *file)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init(const char *filename)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init(const std::string &filename)
+               {
+                       return init(filename.c_str());
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init_ogg(FILE *file)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_ogg_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init_ogg(const char *filename)
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__stream_encoder_init_ogg_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
+               }
+
+               ::FLAC__StreamEncoderInitStatus File::init_ogg(const std::string &filename)
+               {
+                       return init_ogg(filename.c_str());
+               }
+
+               // This is a dummy to satisfy the pure virtual from Stream; the
+               // read callback will never be called since we are initializing
+               // with FLAC__stream_decoder_init_FILE() or
+               // FLAC__stream_decoder_init_file() and those supply the read
+               // callback internally.
+               ::FLAC__StreamEncoderWriteStatus File::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
+               {
+                       (void)buffer, (void)bytes, (void)samples, (void)current_frame;
+                       FLAC__ASSERT(false);
+                       return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; // double protection
+               }
+
+               void File::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
+               {
+                       (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
+               }
+
+               void File::progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+               {
+                       (void)encoder;
+                       FLAC__ASSERT(0 != client_data);
+                       File *instance = reinterpret_cast<File *>(client_data);
+                       FLAC__ASSERT(0 != instance);
+                       instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_estimate);
+               }
+
+       }
+}
diff --git a/src/libFLAC/Makefile.am b/src/libFLAC/Makefile.am
new file mode 100644 (file)
index 0000000..cbfb0ac
--- /dev/null
@@ -0,0 +1,118 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+lib_LTLIBRARIES = libFLAC.la
+if DEBUG
+DEBUGCFLAGS = -DFLAC__OVERFLOW_DETECT
+endif
+if FLaC__CPU_PPC
+# The -force_cpusubtype_ALL is needed to insert a ppc64 instruction
+# into cpu.c with an asm().
+if FLaC__SYS_DARWIN
+#@@@ PPC optimizations temporarily disabled
+CPUCFLAGS = -faltivec -force_cpusubtype_ALL -DFLAC__NO_ASM
+else
+# Linux-gcc for PPC does not have -force_cpusubtype_ALL, it is Darwin-specific
+#@@@ PPC optimizations temporarily disabled
+CPUCFLAGS = -maltivec -mabi=altivec -DFLAC__NO_ASM
+endif
+endif
+
+AM_CFLAGS = $(DEBUGCFLAGS) $(CPUCFLAGS) @OGG_CFLAGS@
+
+if FLaC__NO_ASM
+else
+if FLaC__CPU_IA32
+if FLaC__HAS_NASM
+ARCH_SUBDIRS = ia32
+LOCAL_EXTRA_LIBADD = ia32/libFLAC-asm.la
+endif
+endif
+if FLaC__CPU_PPC
+ARCH_SUBDIRS = ppc
+if FLaC__HAS_AS__TEMPORARILY_DISABLED
+LOCAL_EXTRA_LIBADD = ppc/as/libFLAC-asm.la
+LOCAL_EXTRA_LDFLAGS = "-Wl,-read_only_relocs,warning"
+else
+if FLaC__HAS_GAS__TEMPORARILY_DISABLED
+LOCAL_EXTRA_LIBADD = ppc/gas/libFLAC-asm.la
+LOCAL_EXTRA_LDFLAGS = ""
+endif
+endif
+endif
+endif
+
+libFLAC_la_LIBADD = $(LOCAL_EXTRA_LIBADD) @OGG_LIBS@
+
+SUBDIRS = $(ARCH_SUBDIRS) include .
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac.pc
+
+EXTRA_DIST = \
+       Makefile.lite \
+       flac.pc.in \
+       libFLAC_dynamic.dsp \
+       libFLAC_dynamic.vcproj \
+       libFLAC_static.dsp \
+       libFLAC_static.vcproj \
+       libFLAC.m4
+
+if FLaC__HAS_OGG
+extra_ogg_sources = \
+       ogg_decoder_aspect.c \
+       ogg_encoder_aspect.c \
+       ogg_helper.c \
+       ogg_mapping.c
+endif
+# see 'http://www.gnu.org/software/libtool/manual.html#Libtool-versioning' for numbering convention
+libFLAC_la_LDFLAGS = -version-info 10:0:2 -lm $(LOCAL_EXTRA_LDFLAGS)
+libFLAC_la_SOURCES = \
+       bitmath.c \
+       bitreader.c \
+       bitwriter.c \
+       cpu.c \
+       crc.c \
+       fixed.c \
+       float.c \
+       format.c \
+       lpc.c \
+       md5.c \
+       memory.c \
+       metadata_iterators.c \
+       metadata_object.c \
+       stream_decoder.c \
+       stream_encoder.c \
+       stream_encoder_framing.c \
+       window.c \
+       $(extra_ogg_sources)
diff --git a/src/libFLAC/Makefile.lite b/src/libFLAC/Makefile.lite
new file mode 100644 (file)
index 0000000..8ea37f8
--- /dev/null
@@ -0,0 +1,90 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+LIB_NAME = libFLAC
+ifeq ($(DARWIN_BUILD),yes)
+DEFINES = -DFLAC__CPU_PPC -DFLAC__USE_ALTIVEC -DFLAC__ALIGN_MALLOC_DATA
+else
+ifeq ($(SOLARIS_BUILD),yes)
+DEFINES = -DFLAC__NO_ASM -DFLAC__ALIGN_MALLOC_DATA
+else
+DEFINES = -DFLAC__CPU_IA32 -DFLAC__USE_3DNOW -DFLAC__HAS_NASM -DFLAC__ALIGN_MALLOC_DATA
+endif
+endif
+INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR)
+DEBUG_CFLAGS = -DFLAC__OVERFLOW_DETECT
+
+ifeq ($(DARWIN_BUILD),yes)
+SRCS_S = \
+       ppc/as/lpc_asm.s
+else
+ifeq ($(SOLARIS_BUILD),yes)
+else
+SRCS_NASM = \
+       ia32/bitreader_asm.nasm \
+       ia32/cpu_asm.nasm \
+       ia32/fixed_asm.nasm \
+       ia32/lpc_asm.nasm \
+       ia32/stream_encoder_asm.nasm
+endif
+endif
+
+SRCS_C = \
+       bitmath.c \
+       bitreader.c \
+       bitwriter.c \
+       cpu.c \
+       crc.c \
+       fixed.c \
+       float.c \
+       format.c \
+       lpc.c \
+       md5.c \
+       memory.c \
+       metadata_iterators.c \
+       metadata_object.c \
+       ogg_decoder_aspect.c \
+       ogg_encoder_aspect.c \
+       ogg_helper.c \
+       ogg_mapping.c \
+       stream_decoder.c \
+       stream_encoder.c \
+       stream_encoder_framing.c \
+       window.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/libFLAC/bitmath.c b/src/libFLAC/bitmath.c
new file mode 100644 (file)
index 0000000..27e25f0
--- /dev/null
@@ -0,0 +1,149 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/bitmath.h"
+#include "FLAC/assert.h"
+
+/* An example of what FLAC__bitmath_ilog2() computes:
+ *
+ * ilog2( 0) = assertion failure
+ * ilog2( 1) = 0
+ * ilog2( 2) = 1
+ * ilog2( 3) = 1
+ * ilog2( 4) = 2
+ * ilog2( 5) = 2
+ * ilog2( 6) = 2
+ * ilog2( 7) = 2
+ * ilog2( 8) = 3
+ * ilog2( 9) = 3
+ * ilog2(10) = 3
+ * ilog2(11) = 3
+ * ilog2(12) = 3
+ * ilog2(13) = 3
+ * ilog2(14) = 3
+ * ilog2(15) = 3
+ * ilog2(16) = 4
+ * ilog2(17) = 4
+ * ilog2(18) = 4
+ */
+unsigned FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+       unsigned l = 0;
+       FLAC__ASSERT(v > 0);
+       while(v >>= 1)
+               l++;
+       return l;
+}
+
+unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+       unsigned l = 0;
+       FLAC__ASSERT(v > 0);
+       while(v >>= 1)
+               l++;
+       return l;
+}
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2(  0) = 0
+ * silog2(  1) = 2
+ * silog2(  2) = 3
+ * silog2(  3) = 3
+ * silog2(  4) = 4
+ * silog2(  5) = 4
+ * silog2(  6) = 4
+ * silog2(  7) = 4
+ * silog2(  8) = 5
+ * silog2(  9) = 5
+ * silog2( 10) = 5
+ */
+unsigned FLAC__bitmath_silog2(int v)
+{
+       while(1) {
+               if(v == 0) {
+                       return 0;
+               }
+               else if(v > 0) {
+                       unsigned l = 0;
+                       while(v) {
+                               l++;
+                               v >>= 1;
+                       }
+                       return l+1;
+               }
+               else if(v == -1) {
+                       return 2;
+               }
+               else {
+                       v++;
+                       v = -v;
+               }
+       }
+}
+
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v)
+{
+       while(1) {
+               if(v == 0) {
+                       return 0;
+               }
+               else if(v > 0) {
+                       unsigned l = 0;
+                       while(v) {
+                               l++;
+                               v >>= 1;
+                       }
+                       return l+1;
+               }
+               else if(v == -1) {
+                       return 2;
+               }
+               else {
+                       v++;
+                       v = -v;
+               }
+       }
+}
diff --git a/src/libFLAC/bitreader.c b/src/libFLAC/bitreader.c
new file mode 100644 (file)
index 0000000..7d63e52
--- /dev/null
@@ -0,0 +1,1376 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+#ifdef _MSC_VER
+#include <winsock.h> /* for ntohl() */
+#elif defined FLAC__SYS_DARWIN
+#include <machine/endian.h> /* for ntohl() */
+#elif defined __MINGW32__
+#include <winsock.h> /* for ntohl() */
+#else
+#include <netinet/in.h> /* for ntohl() */
+#endif
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS below to match */
+/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
+/*           also, some sections currently only have fast versions for 4 or 8 bytes per word */
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#if WORDS_BIGENDIAN
+#define SWAP_BE_WORD_TO_HOST(x) (x)
+#else
+#ifdef _MSC_VER
+#define SWAP_BE_WORD_TO_HOST(x) local_swap32_(x)
+#else
+#define SWAP_BE_WORD_TO_HOST(x) ntohl(x)
+#endif
+#endif
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) ( \
+       (word) <= 0xffff ? \
+               ( (word) <= 0xff? byte_to_unary_table[word] + 24 : byte_to_unary_table[(word) >> 8] + 16 ) : \
+               ( (word) <= 0xffffff? byte_to_unary_table[word >> 16] + 8 : byte_to_unary_table[(word) >> 24] ) \
+)
+/* this alternate might be slightly faster on some systems/compilers: */
+#define COUNT_ZERO_MSBS2(word) ( (word) <= 0xff ? byte_to_unary_table[word] + 24 : ((word) <= 0xffff ? byte_to_unary_table[(word) >> 8] + 16 : ((word) <= 0xffffff ? byte_to_unary_table[(word) >> 16] + 8 : byte_to_unary_table[(word) >> 24])) )
+
+
+/*
+ * This should be at least twice as large as the largest number of words
+ * required to represent any 'number' (in any encoding) you are going to
+ * read.  With FLAC this is on the order of maybe a few hundred bits.
+ * If the buffer is smaller than that, the decoder won't be able to read
+ * in a whole number that is in a variable length encoding (e.g. Rice).
+ * But to be practical it should be at least 1K bytes.
+ *
+ * Increase this number to decrease the number of read callbacks, at the
+ * expense of using more memory.  Or decrease for the reverse effect,
+ * keeping in mind the limit from the first paragraph.  The optimal size
+ * also depends on the CPU cache size and other factors; some twiddling
+ * may be necessary to squeeze out the best performance.
+ */
+static const unsigned FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+static const unsigned char byte_to_unary_table[] = {
+       8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/* WATCHOUT: assembly routines rely on the order in which these fields are declared */
+struct FLAC__BitReader {
+       /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */
+       /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */
+       brword *buffer;
+       unsigned capacity; /* in words */
+       unsigned words; /* # of completed words in buffer */
+       unsigned bytes; /* # of bytes in incomplete word at buffer[words] */
+       unsigned consumed_words; /* #words ... */
+       unsigned consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+       unsigned read_crc16; /* the running frame CRC */
+       unsigned crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+       FLAC__BitReaderReadCallback read_callback;
+       void *client_data;
+       FLAC__CPUInfo cpu_info;
+};
+
+#ifdef _MSC_VER
+/* OPT: an MSVC built-in would be better */
+static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x)
+{
+       x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
+       return (x>>16) | (x<<16);
+}
+static void local_swap32_block_(FLAC__uint32 *start, FLAC__uint32 len)
+{
+       __asm {
+               mov edx, start
+               mov ecx, len
+               test ecx, ecx
+loop1:
+               jz done1
+               mov eax, [edx]
+               bswap eax
+               mov [edx], eax
+               add edx, 4
+               dec ecx
+               jmp short loop1
+done1:
+       }
+}
+#endif
+
+static FLaC__INLINE void crc16_update_word_(FLAC__BitReader *br, brword word)
+{
+       register unsigned crc = br->read_crc16;
+#if FLAC__BYTES_PER_WORD == 4
+       switch(br->crc16_align) {
+               case  0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 24), crc);
+               case  8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+               case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+               case 24: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+       }
+#elif FLAC__BYTES_PER_WORD == 8
+       switch(br->crc16_align) {
+               case  0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 56), crc);
+               case  8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 48) & 0xff), crc);
+               case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 40) & 0xff), crc);
+               case 24: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 32) & 0xff), crc);
+               case 32: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 24) & 0xff), crc);
+               case 40: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+               case 48: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+               case 56: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+       }
+#else
+       for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8)
+               crc = FLAC__CRC16_UPDATE((unsigned)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc);
+       br->read_crc16 = crc;
+#endif
+       br->crc16_align = 0;
+}
+
+/* would be static except it needs to be called by asm routines */
+FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+       unsigned start, end;
+       size_t bytes;
+       FLAC__byte *target;
+
+       /* first shift the unconsumed buffer data toward the front as much as possible */
+       if(br->consumed_words > 0) {
+               start = br->consumed_words;
+               end = br->words + (br->bytes? 1:0);
+               memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start));
+
+               br->words -= start;
+               br->consumed_words = 0;
+       }
+
+       /*
+        * set the target for reading, taking into account word alignment and endianness
+        */
+       bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes;
+       if(bytes == 0)
+               return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY  */
+       target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes;
+
+       /* before reading, if the existing reader looks like this (say brword is 32 bits wide)
+        *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1 (partial tail word is left-justified)
+        *   buffer[BE]:  11 22 33 44 55 ?? ?? ??   (shown layed out as bytes sequentially in memory)
+        *   buffer[LE]:  44 33 22 11 ?? ?? ?? 55   (?? being don't-care)
+        *                               ^^-------target, bytes=3
+        * on LE machines, have to byteswap the odd tail word so nothing is
+        * overwritten:
+        */
+#if WORDS_BIGENDIAN
+#else
+       if(br->bytes)
+               br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]);
+#endif
+
+       /* now it looks like:
+        *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1
+        *   buffer[BE]:  11 22 33 44 55 ?? ?? ??
+        *   buffer[LE]:  44 33 22 11 55 ?? ?? ??
+        *                               ^^-------target, bytes=3
+        */
+
+       /* read in the data; note that the callback may return a smaller number of bytes */
+       if(!br->read_callback(target, &bytes, br->client_data))
+               return false;
+
+       /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client:
+        *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+        *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+        *   buffer[LE]:  44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ??
+        * now have to byteswap on LE machines:
+        */
+#if WORDS_BIGENDIAN
+#else
+       end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+# if defined(_MSC_VER) && (FLAC__BYTES_PER_WORD == 4)
+       if(br->cpu_info.type == FLAC__CPUINFO_TYPE_IA32 && br->cpu_info.data.ia32.bswap) {
+               start = br->words;
+               local_swap32_block_(br->buffer + start, end - start);
+       }
+       else
+# endif
+       for(start = br->words; start < end; start++)
+               br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]);
+#endif
+
+       /* now it looks like:
+        *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+        *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+        *   buffer[LE]:  44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD
+        * finally we'll update the reader values:
+        */
+       end = br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes;
+       br->words = end / FLAC__BYTES_PER_WORD;
+       br->bytes = end % FLAC__BYTES_PER_WORD;
+
+       return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitReader *FLAC__bitreader_new(void)
+{
+       FLAC__BitReader *br = (FLAC__BitReader*)calloc(1, sizeof(FLAC__BitReader));
+
+       /* calloc() implies:
+               memset(br, 0, sizeof(FLAC__BitReader));
+               br->buffer = 0;
+               br->capacity = 0;
+               br->words = br->bytes = 0;
+               br->consumed_words = br->consumed_bits = 0;
+               br->read_callback = 0;
+               br->client_data = 0;
+       */
+       return br;
+}
+
+void FLAC__bitreader_delete(FLAC__BitReader *br)
+{
+       FLAC__ASSERT(0 != br);
+
+       FLAC__bitreader_free(br);
+       free(br);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd)
+{
+       FLAC__ASSERT(0 != br);
+
+       br->words = br->bytes = 0;
+       br->consumed_words = br->consumed_bits = 0;
+       br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY;
+       br->buffer = (brword*)malloc(sizeof(brword) * br->capacity);
+       if(br->buffer == 0)
+               return false;
+       br->read_callback = rcb;
+       br->client_data = cd;
+       br->cpu_info = cpu;
+
+       return true;
+}
+
+void FLAC__bitreader_free(FLAC__BitReader *br)
+{
+       FLAC__ASSERT(0 != br);
+
+       if(0 != br->buffer)
+               free(br->buffer);
+       br->buffer = 0;
+       br->capacity = 0;
+       br->words = br->bytes = 0;
+       br->consumed_words = br->consumed_bits = 0;
+       br->read_callback = 0;
+       br->client_data = 0;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+       br->words = br->bytes = 0;
+       br->consumed_words = br->consumed_bits = 0;
+       return true;
+}
+
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+       unsigned i, j;
+       if(br == 0) {
+               fprintf(out, "bitreader is NULL\n");
+       }
+       else {
+               fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits);
+
+               for(i = 0; i < br->words; i++) {
+                       fprintf(out, "%08X: ", i);
+                       for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+                               if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+                                       fprintf(out, ".");
+                               else
+                                       fprintf(out, "%01u", br->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+                       fprintf(out, "\n");
+               }
+               if(br->bytes > 0) {
+                       fprintf(out, "%08X: ", i);
+                       for(j = 0; j < br->bytes*8; j++)
+                               if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+                                       fprintf(out, ".");
+                               else
+                                       fprintf(out, "%01u", br->buffer[i] & (1 << (br->bytes*8-j-1)) ? 1:0);
+                       fprintf(out, "\n");
+               }
+       }
+}
+
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed)
+{
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       FLAC__ASSERT((br->consumed_bits & 7) == 0);
+
+       br->read_crc16 = (unsigned)seed;
+       br->crc16_align = br->consumed_bits;
+}
+
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br)
+{
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       FLAC__ASSERT((br->consumed_bits & 7) == 0);
+       FLAC__ASSERT(br->crc16_align <= br->consumed_bits);
+
+       /* CRC any tail bytes in a partially-consumed word */
+       if(br->consumed_bits) {
+               const brword tail = br->buffer[br->consumed_words];
+               for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+                       br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+       }
+       return br->read_crc16;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+       return ((br->consumed_bits & 7) == 0);
+}
+
+FLaC__INLINE unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+       return 8 - (br->consumed_bits & 7);
+}
+
+FLaC__INLINE unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br)
+{
+       return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits)
+{
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       FLAC__ASSERT(bits <= 32);
+       FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits);
+       FLAC__ASSERT(br->consumed_words <= br->words);
+
+       /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+       FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+       if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */
+               *val = 0;
+               return true;
+       }
+
+       while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) {
+               if(!bitreader_read_from_client_(br))
+                       return false;
+       }
+       if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+               /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+               if(br->consumed_bits) {
+                       /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                       const unsigned n = FLAC__BITS_PER_WORD - br->consumed_bits;
+                       const brword word = br->buffer[br->consumed_words];
+                       if(bits < n) {
+                               *val = (word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits);
+                               br->consumed_bits += bits;
+                               return true;
+                       }
+                       *val = word & (FLAC__WORD_ALL_ONES >> br->consumed_bits);
+                       bits -= n;
+                       crc16_update_word_(br, word);
+                       br->consumed_words++;
+                       br->consumed_bits = 0;
+                       if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+                               *val <<= bits;
+                               *val |= (br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+                               br->consumed_bits = bits;
+                       }
+                       return true;
+               }
+               else {
+                       const brword word = br->buffer[br->consumed_words];
+                       if(bits < FLAC__BITS_PER_WORD) {
+                               *val = word >> (FLAC__BITS_PER_WORD-bits);
+                               br->consumed_bits = bits;
+                               return true;
+                       }
+                       /* at this point 'bits' must be == FLAC__BITS_PER_WORD; because of previous assertions, it can't be larger */
+                       *val = word;
+                       crc16_update_word_(br, word);
+                       br->consumed_words++;
+                       return true;
+               }
+       }
+       else {
+               /* in this case we're starting our read at a partial tail word;
+                * the reader has guaranteed that we have at least 'bits' bits
+                * available to read, which makes this case simpler.
+                */
+               /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+               if(br->consumed_bits) {
+                       /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                       FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8);
+                       *val = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits);
+                       br->consumed_bits += bits;
+                       return true;
+               }
+               else {
+                       *val = br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits);
+                       br->consumed_bits += bits;
+                       return true;
+               }
+       }
+}
+
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits)
+{
+       /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+       if(!FLAC__bitreader_read_raw_uint32(br, (FLAC__uint32*)val, bits))
+               return false;
+       /* sign-extend: */
+       *val <<= (32-bits);
+       *val >>= (32-bits);
+       return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits)
+{
+       FLAC__uint32 hi, lo;
+
+       if(bits > 32) {
+               if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32))
+                       return false;
+               if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32))
+                       return false;
+               *val = hi;
+               *val <<= 32;
+               *val |= lo;
+       }
+       else {
+               if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits))
+                       return false;
+               *val = lo;
+       }
+       return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val)
+{
+       FLAC__uint32 x8, x32 = 0;
+
+       /* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8))
+               return false;
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+               return false;
+       x32 |= (x8 << 8);
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+               return false;
+       x32 |= (x8 << 16);
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+               return false;
+       x32 |= (x8 << 24);
+
+       *val = x32;
+       return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits)
+{
+       /*
+        * OPT: a faster implementation is possible but probably not that useful
+        * since this is only called a couple of times in the metadata readers.
+        */
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       if(bits > 0) {
+               const unsigned n = br->consumed_bits & 7;
+               unsigned m;
+               FLAC__uint32 x;
+
+               if(n != 0) {
+                       m = min(8-n, bits);
+                       if(!FLAC__bitreader_read_raw_uint32(br, &x, m))
+                               return false;
+                       bits -= m;
+               }
+               m = bits / 8;
+               if(m > 0) {
+                       if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m))
+                               return false;
+                       bits %= 8;
+               }
+               if(bits > 0) {
+                       if(!FLAC__bitreader_read_raw_uint32(br, &x, bits))
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals)
+{
+       FLAC__uint32 x;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+       /* step 1: skip over partial head word to get word aligned */
+       while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               nvals--;
+       }
+       if(0 == nvals)
+               return true;
+       /* step 2: skip whole words in chunks */
+       while(nvals >= FLAC__BYTES_PER_WORD) {
+               if(br->consumed_words < br->words) {
+                       br->consumed_words++;
+                       nvals -= FLAC__BYTES_PER_WORD;
+               }
+               else if(!bitreader_read_from_client_(br))
+                       return false;
+       }
+       /* step 3: skip any remainder from partial tail bytes */
+       while(nvals) {
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               nvals--;
+       }
+
+       return true;
+}
+
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals)
+{
+       FLAC__uint32 x;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+       /* step 1: read from partial head word to get word aligned */
+       while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               *val++ = (FLAC__byte)x;
+               nvals--;
+       }
+       if(0 == nvals)
+               return true;
+       /* step 2: read whole words in chunks */
+       while(nvals >= FLAC__BYTES_PER_WORD) {
+               if(br->consumed_words < br->words) {
+                       const brword word = br->buffer[br->consumed_words++];
+#if FLAC__BYTES_PER_WORD == 4
+                       val[0] = (FLAC__byte)(word >> 24);
+                       val[1] = (FLAC__byte)(word >> 16);
+                       val[2] = (FLAC__byte)(word >> 8);
+                       val[3] = (FLAC__byte)word;
+#elif FLAC__BYTES_PER_WORD == 8
+                       val[0] = (FLAC__byte)(word >> 56);
+                       val[1] = (FLAC__byte)(word >> 48);
+                       val[2] = (FLAC__byte)(word >> 40);
+                       val[3] = (FLAC__byte)(word >> 32);
+                       val[4] = (FLAC__byte)(word >> 24);
+                       val[5] = (FLAC__byte)(word >> 16);
+                       val[6] = (FLAC__byte)(word >> 8);
+                       val[7] = (FLAC__byte)word;
+#else
+                       for(x = 0; x < FLAC__BYTES_PER_WORD; x++)
+                               val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1)));
+#endif
+                       val += FLAC__BYTES_PER_WORD;
+                       nvals -= FLAC__BYTES_PER_WORD;
+               }
+               else if(!bitreader_read_from_client_(br))
+                       return false;
+       }
+       /* step 3: read any remainder from partial tail bytes */
+       while(nvals) {
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               *val++ = (FLAC__byte)x;
+               nvals--;
+       }
+
+       return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val)
+#if 0 /* slow but readable version */
+{
+       unsigned bit;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       *val = 0;
+       while(1) {
+               if(!FLAC__bitreader_read_bit(br, &bit))
+                       return false;
+               if(bit)
+                       break;
+               else
+                       *val++;
+       }
+       return true;
+}
+#else
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       *val = 0;
+       while(1) {
+               while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+                       brword b = br->buffer[br->consumed_words] << br->consumed_bits;
+                       if(b) {
+                               i = COUNT_ZERO_MSBS(b);
+                               *val += i;
+                               i++;
+                               br->consumed_bits += i;
+                               if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */
+                                       crc16_update_word_(br, br->buffer[br->consumed_words]);
+                                       br->consumed_words++;
+                                       br->consumed_bits = 0;
+                               }
+                               return true;
+                       }
+                       else {
+                               *val += FLAC__BITS_PER_WORD - br->consumed_bits;
+                               crc16_update_word_(br, br->buffer[br->consumed_words]);
+                               br->consumed_words++;
+                               br->consumed_bits = 0;
+                               /* didn't find stop bit yet, have to keep going... */
+                       }
+               }
+               /* at this point we've eaten up all the whole words; have to try
+                * reading through any tail bytes before calling the read callback.
+                * this is a repeat of the above logic adjusted for the fact we
+                * don't have a whole word.  note though if the client is feeding
+                * us data a byte at a time (unlikely), br->consumed_bits may not
+                * be zero.
+                */
+               if(br->bytes) {
+                       const unsigned end = br->bytes * 8;
+                       brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+                       if(b) {
+                               i = COUNT_ZERO_MSBS(b);
+                               *val += i;
+                               i++;
+                               br->consumed_bits += i;
+                               FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+                               return true;
+                       }
+                       else {
+                               *val += end - br->consumed_bits;
+                               br->consumed_bits += end;
+                               FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+                               /* didn't find stop bit yet, have to keep going... */
+                       }
+               }
+               if(!bitreader_read_from_client_(br))
+                       return false;
+       }
+}
+#endif
+
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+       FLAC__uint32 lsbs = 0, msbs = 0;
+       unsigned uval;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       FLAC__ASSERT(parameter <= 31);
+
+       /* read the unary MSBs and end bit */
+       if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+               return false;
+
+       /* read the binary LSBs */
+       if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter))
+               return false;
+
+       /* compose the value */
+       uval = (msbs << parameter) | lsbs;
+       if(uval & 1)
+               *val = -((int)(uval >> 1)) - 1;
+       else
+               *val = (int)(uval >> 1);
+
+       return true;
+}
+
+/* this is by far the most heavily used reader call.  it ain't pretty but it's fast */
+/* a lot of the logic is copied, then adapted, from FLAC__bitreader_read_unary_unsigned() and FLAC__bitreader_read_raw_uint32() */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+/* OPT: possibly faster version for use with MSVC */
+#ifdef _MSC_VER
+{
+       unsigned i;
+       unsigned uval = 0;
+       unsigned bits; /* the # of binary LSBs left to read to finish a rice codeword */
+
+       /* try and get br->consumed_words and br->consumed_bits into register;
+        * must remember to flush them back to *br before calling other
+        * bitwriter functions that use them, and before returning */
+       register unsigned cwords;
+       register unsigned cbits;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+       FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+       FLAC__ASSERT(parameter < 32);
+       /* the above two asserts also guarantee that the binary part never straddles more that 2 words, so we don't have to loop to read it */
+
+       if(nvals == 0)
+               return true;
+
+       cbits = br->consumed_bits;
+       cwords = br->consumed_words;
+
+       while(1) {
+
+               /* read unary part */
+               while(1) {
+                       while(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+                               brword b = br->buffer[cwords] << cbits;
+                               if(b) {
+#if 0 /* slower, probably due to bad register allocation... */ && defined FLAC__CPU_IA32 && !defined FLAC__NO_ASM && FLAC__BITS_PER_WORD == 32
+                                       __asm {
+                                               bsr eax, b
+                                               not eax
+                                               and eax, 31
+                                               mov i, eax
+                                       }
+#else
+                                       i = COUNT_ZERO_MSBS(b);
+#endif
+                                       uval += i;
+                                       bits = parameter;
+                                       i++;
+                                       cbits += i;
+                                       if(cbits == FLAC__BITS_PER_WORD) {
+                                               crc16_update_word_(br, br->buffer[cwords]);
+                                               cwords++;
+                                               cbits = 0;
+                                       }
+                                       goto break1;
+                               }
+                               else {
+                                       uval += FLAC__BITS_PER_WORD - cbits;
+                                       crc16_update_word_(br, br->buffer[cwords]);
+                                       cwords++;
+                                       cbits = 0;
+                                       /* didn't find stop bit yet, have to keep going... */
+                               }
+                       }
+                       /* at this point we've eaten up all the whole words; have to try
+                        * reading through any tail bytes before calling the read callback.
+                        * this is a repeat of the above logic adjusted for the fact we
+                        * don't have a whole word.  note though if the client is feeding
+                        * us data a byte at a time (unlikely), br->consumed_bits may not
+                        * be zero.
+                        */
+                       if(br->bytes) {
+                               const unsigned end = br->bytes * 8;
+                               brword b = (br->buffer[cwords] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << cbits;
+                               if(b) {
+                                       i = COUNT_ZERO_MSBS(b);
+                                       uval += i;
+                                       bits = parameter;
+                                       i++;
+                                       cbits += i;
+                                       FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+                                       goto break1;
+                               }
+                               else {
+                                       uval += end - cbits;
+                                       cbits += end;
+                                       FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+                                       /* didn't find stop bit yet, have to keep going... */
+                               }
+                       }
+                       /* flush registers and read; bitreader_read_from_client_() does
+                        * not touch br->consumed_bits at all but we still need to set
+                        * it in case it fails and we have to return false.
+                        */
+                       br->consumed_bits = cbits;
+                       br->consumed_words = cwords;
+                       if(!bitreader_read_from_client_(br))
+                               return false;
+                       cwords = br->consumed_words;
+               }
+break1:
+               /* read binary part */
+               FLAC__ASSERT(cwords <= br->words);
+
+               if(bits) {
+                       while((br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits < bits) {
+                               /* flush registers and read; bitreader_read_from_client_() does
+                                * not touch br->consumed_bits at all but we still need to set
+                                * it in case it fails and we have to return false.
+                                */
+                               br->consumed_bits = cbits;
+                               br->consumed_words = cwords;
+                               if(!bitreader_read_from_client_(br))
+                                       return false;
+                               cwords = br->consumed_words;
+                       }
+                       if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+                               if(cbits) {
+                                       /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                                       const unsigned n = FLAC__BITS_PER_WORD - cbits;
+                                       const brword word = br->buffer[cwords];
+                                       if(bits < n) {
+                                               uval <<= bits;
+                                               uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-bits);
+                                               cbits += bits;
+                                               goto break2;
+                                       }
+                                       uval <<= n;
+                                       uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+                                       bits -= n;
+                                       crc16_update_word_(br, word);
+                                       cwords++;
+                                       cbits = 0;
+                                       if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+                                               uval <<= bits;
+                                               uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits));
+                                               cbits = bits;
+                                       }
+                                       goto break2;
+                               }
+                               else {
+                                       FLAC__ASSERT(bits < FLAC__BITS_PER_WORD);
+                                       uval <<= bits;
+                                       uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits);
+                                       cbits = bits;
+                                       goto break2;
+                               }
+                       }
+                       else {
+                               /* in this case we're starting our read at a partial tail word;
+                                * the reader has guaranteed that we have at least 'bits' bits
+                                * available to read, which makes this case simpler.
+                                */
+                               uval <<= bits;
+                               if(cbits) {
+                                       /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                                       FLAC__ASSERT(cbits + bits <= br->bytes*8);
+                                       uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-bits);
+                                       cbits += bits;
+                                       goto break2;
+                               }
+                               else {
+                                       uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits);
+                                       cbits += bits;
+                                       goto break2;
+                               }
+                       }
+               }
+break2:
+               /* compose the value */
+               *vals = (int)(uval >> 1 ^ -(int)(uval & 1));
+
+               /* are we done? */
+               --nvals;
+               if(nvals == 0) {
+                       br->consumed_bits = cbits;
+                       br->consumed_words = cwords;
+                       return true;
+               }
+
+               uval = 0;
+               ++vals;
+
+       }
+}
+#else
+{
+       unsigned i;
+       unsigned uval = 0;
+
+       /* try and get br->consumed_words and br->consumed_bits into register;
+        * must remember to flush them back to *br before calling other
+        * bitwriter functions that use them, and before returning */
+       register unsigned cwords;
+       register unsigned cbits;
+       unsigned ucbits; /* keep track of the number of unconsumed bits in the buffer */
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+       /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+       FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+       FLAC__ASSERT(parameter < 32);
+       /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */
+
+       if(nvals == 0)
+               return true;
+
+       cbits = br->consumed_bits;
+       cwords = br->consumed_words;
+       ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+
+       while(1) {
+
+               /* read unary part */
+               while(1) {
+                       while(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+                               brword b = br->buffer[cwords] << cbits;
+                               if(b) {
+#if 0 /* is not discernably faster... */ && defined FLAC__CPU_IA32 && !defined FLAC__NO_ASM && FLAC__BITS_PER_WORD == 32 && defined __GNUC__
+                                       asm volatile (
+                                               "bsrl %1, %0;"
+                                               "notl %0;"
+                                               "andl $31, %0;"
+                                               : "=r"(i)
+                                               : "r"(b)
+                                       );
+#else
+                                       i = COUNT_ZERO_MSBS(b);
+#endif
+                                       uval += i;
+                                       cbits += i;
+                                       cbits++; /* skip over stop bit */
+                                       if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
+                                               crc16_update_word_(br, br->buffer[cwords]);
+                                               cwords++;
+                                               cbits = 0;
+                                       }
+                                       goto break1;
+                               }
+                               else {
+                                       uval += FLAC__BITS_PER_WORD - cbits;
+                                       crc16_update_word_(br, br->buffer[cwords]);
+                                       cwords++;
+                                       cbits = 0;
+                                       /* didn't find stop bit yet, have to keep going... */
+                               }
+                       }
+                       /* at this point we've eaten up all the whole words; have to try
+                        * reading through any tail bytes before calling the read callback.
+                        * this is a repeat of the above logic adjusted for the fact we
+                        * don't have a whole word.  note though if the client is feeding
+                        * us data a byte at a time (unlikely), br->consumed_bits may not
+                        * be zero.
+                        */
+                       if(br->bytes) {
+                               const unsigned end = br->bytes * 8;
+                               brword b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
+                               if(b) {
+                                       i = COUNT_ZERO_MSBS(b);
+                                       uval += i;
+                                       cbits += i;
+                                       cbits++; /* skip over stop bit */
+                                       FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+                                       goto break1;
+                               }
+                               else {
+                                       uval += end - cbits;
+                                       cbits += end;
+                                       FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+                                       /* didn't find stop bit yet, have to keep going... */
+                               }
+                       }
+                       /* flush registers and read; bitreader_read_from_client_() does
+                        * not touch br->consumed_bits at all but we still need to set
+                        * it in case it fails and we have to return false.
+                        */
+                       br->consumed_bits = cbits;
+                       br->consumed_words = cwords;
+                       if(!bitreader_read_from_client_(br))
+                               return false;
+                       cwords = br->consumed_words;
+                       ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval;
+                       /* + uval to offset our count by the # of unary bits already
+                        * consumed before the read, because we will add these back
+                        * in all at once at break1
+                        */
+               }
+break1:
+               ucbits -= uval;
+               ucbits--; /* account for stop bit */
+
+               /* read binary part */
+               FLAC__ASSERT(cwords <= br->words);
+
+               if(parameter) {
+                       while(ucbits < parameter) {
+                               /* flush registers and read; bitreader_read_from_client_() does
+                                * not touch br->consumed_bits at all but we still need to set
+                                * it in case it fails and we have to return false.
+                                */
+                               br->consumed_bits = cbits;
+                               br->consumed_words = cwords;
+                               if(!bitreader_read_from_client_(br))
+                                       return false;
+                               cwords = br->consumed_words;
+                               ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+                       }
+                       if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+                               if(cbits) {
+                                       /* this also works when consumed_bits==0, it's just slower than necessary for that case */
+                                       const unsigned n = FLAC__BITS_PER_WORD - cbits;
+                                       const brword word = br->buffer[cwords];
+                                       if(parameter < n) {
+                                               uval <<= parameter;
+                                               uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
+                                               cbits += parameter;
+                                       }
+                                       else {
+                                               uval <<= n;
+                                               uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+                                               crc16_update_word_(br, word);
+                                               cwords++;
+                                               cbits = parameter - n;
+                                               if(cbits) { /* parameter > n, i.e. if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+                                                       uval <<= cbits;
+                                                       uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+                                               }
+                                       }
+                               }
+                               else {
+                                       cbits = parameter;
+                                       uval <<= parameter;
+                                       uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+                               }
+                       }
+                       else {
+                               /* in this case we're starting our read at a partial tail word;
+                                * the reader has guaranteed that we have at least 'parameter'
+                                * bits available to read, which makes this case simpler.
+                                */
+                               uval <<= parameter;
+                               if(cbits) {
+                                       /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                                       FLAC__ASSERT(cbits + parameter <= br->bytes*8);
+                                       uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
+                                       cbits += parameter;
+                               }
+                               else {
+                                       cbits = parameter;
+                                       uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+                               }
+                       }
+               }
+
+               ucbits -= parameter;
+
+               /* compose the value */
+               *vals = (int)(uval >> 1 ^ -(int)(uval & 1));
+
+               /* are we done? */
+               --nvals;
+               if(nvals == 0) {
+                       br->consumed_bits = cbits;
+                       br->consumed_words = cwords;
+                       return true;
+               }
+
+               uval = 0;
+               ++vals;
+
+       }
+}
+#endif
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+       FLAC__uint32 lsbs = 0, msbs = 0;
+       unsigned bit, uval, k;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       k = FLAC__bitmath_ilog2(parameter);
+
+       /* read the unary MSBs and end bit */
+       if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+               return false;
+
+       /* read the binary LSBs */
+       if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+               return false;
+
+       if(parameter == 1u<<k) {
+               /* compose the value */
+               uval = (msbs << k) | lsbs;
+       }
+       else {
+               unsigned d = (1 << (k+1)) - parameter;
+               if(lsbs >= d) {
+                       if(!FLAC__bitreader_read_bit(br, &bit))
+                               return false;
+                       lsbs <<= 1;
+                       lsbs |= bit;
+                       lsbs -= d;
+               }
+               /* compose the value */
+               uval = msbs * parameter + lsbs;
+       }
+
+       /* unfold unsigned to signed */
+       if(uval & 1)
+               *val = -((int)(uval >> 1)) - 1;
+       else
+               *val = (int)(uval >> 1);
+
+       return true;
+}
+
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter)
+{
+       FLAC__uint32 lsbs, msbs = 0;
+       unsigned bit, k;
+
+       FLAC__ASSERT(0 != br);
+       FLAC__ASSERT(0 != br->buffer);
+
+       k = FLAC__bitmath_ilog2(parameter);
+
+       /* read the unary MSBs and end bit */
+       if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+               return false;
+
+       /* read the binary LSBs */
+       if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+               return false;
+
+       if(parameter == 1u<<k) {
+               /* compose the value */
+               *val = (msbs << k) | lsbs;
+       }
+       else {
+               unsigned d = (1 << (k+1)) - parameter;
+               if(lsbs >= d) {
+                       if(!FLAC__bitreader_read_bit(br, &bit))
+                               return false;
+                       lsbs <<= 1;
+                       lsbs |= bit;
+                       lsbs -= d;
+               }
+               /* compose the value */
+               *val = msbs * parameter + lsbs;
+       }
+
+       return true;
+}
+#endif /* UNUSED */
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+       FLAC__uint32 v = 0;
+       FLAC__uint32 x;
+       unsigned i;
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+               return false;
+       if(raw)
+               raw[(*rawlen)++] = (FLAC__byte)x;
+       if(!(x & 0x80)) { /* 0xxxxxxx */
+               v = x;
+               i = 0;
+       }
+       else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+               v = x & 0x1F;
+               i = 1;
+       }
+       else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+               v = x & 0x0F;
+               i = 2;
+       }
+       else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+               v = x & 0x07;
+               i = 3;
+       }
+       else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+               v = x & 0x03;
+               i = 4;
+       }
+       else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+               v = x & 0x01;
+               i = 5;
+       }
+       else {
+               *val = 0xffffffff;
+               return true;
+       }
+       for( ; i; i--) {
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               if(raw)
+                       raw[(*rawlen)++] = (FLAC__byte)x;
+               if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+                       *val = 0xffffffff;
+                       return true;
+               }
+               v <<= 6;
+               v |= (x & 0x3F);
+       }
+       *val = v;
+       return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+       FLAC__uint64 v = 0;
+       FLAC__uint32 x;
+       unsigned i;
+
+       if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+               return false;
+       if(raw)
+               raw[(*rawlen)++] = (FLAC__byte)x;
+       if(!(x & 0x80)) { /* 0xxxxxxx */
+               v = x;
+               i = 0;
+       }
+       else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+               v = x & 0x1F;
+               i = 1;
+       }
+       else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+               v = x & 0x0F;
+               i = 2;
+       }
+       else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+               v = x & 0x07;
+               i = 3;
+       }
+       else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+               v = x & 0x03;
+               i = 4;
+       }
+       else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+               v = x & 0x01;
+               i = 5;
+       }
+       else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */
+               v = 0;
+               i = 6;
+       }
+       else {
+               *val = FLAC__U64L(0xffffffffffffffff);
+               return true;
+       }
+       for( ; i; i--) {
+               if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+                       return false;
+               if(raw)
+                       raw[(*rawlen)++] = (FLAC__byte)x;
+               if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+                       *val = FLAC__U64L(0xffffffffffffffff);
+                       return true;
+               }
+               v <<= 6;
+               v |= (x & 0x3F);
+       }
+       *val = v;
+       return true;
+}
diff --git a/src/libFLAC/bitwriter.c b/src/libFLAC/bitwriter.c
new file mode 100755 (executable)
index 0000000..e3e7ad1
--- /dev/null
@@ -0,0 +1,889 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+#ifdef _MSC_VER
+#include <winsock.h> /* for ntohl() */
+#elif defined FLAC__SYS_DARWIN
+#include <machine/endian.h> /* for ntohl() */
+#elif defined __MINGW32__
+#include <winsock.h> /* for ntohl() */
+#else
+#include <netinet/in.h> /* for ntohl() */
+#endif
+#if 0 /* UNUSED */
+#include "private/bitmath.h"
+#endif
+#include "private/bitwriter.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */
+/* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */
+typedef FLAC__uint32 bwword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */
+#if WORDS_BIGENDIAN
+#define SWAP_BE_WORD_TO_HOST(x) (x)
+#else
+#ifdef _MSC_VER
+#define SWAP_BE_WORD_TO_HOST(x) local_swap32_(x)
+#else
+#define SWAP_BE_WORD_TO_HOST(x) ntohl(x)
+#endif
+#endif
+
+/*
+ * The default capacity here doesn't matter too much.  The buffer always grows
+ * to hold whatever is written to it.  Usually the encoder will stop adding at
+ * a frame or metadata block, then write that out and clear the buffer for the
+ * next one.
+ */
+static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */
+/* When growing, increment 4K at a time */
+static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */
+
+#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
+#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits)
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+struct FLAC__BitWriter {
+       bwword *buffer;
+       bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+       unsigned capacity; /* capacity of buffer in words */
+       unsigned words; /* # of complete words in buffer */
+       unsigned bits; /* # of used bits in accum */
+};
+
+#ifdef _MSC_VER
+/* OPT: an MSVC built-in would be better */
+static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x)
+{
+       x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
+       return (x>>16) | (x<<16);
+}
+#endif
+
+/* * WATCHOUT: The current implementation only grows the buffer. */
+static FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add)
+{
+       unsigned new_capacity;
+       bwword *new_buffer;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+
+       /* calculate total words needed to store 'bits_to_add' additional bits */
+       new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD);
+
+       /* it's possible (due to pessimism in the growth estimation that
+        * leads to this call) that we don't actually need to grow
+        */
+       if(bw->capacity >= new_capacity)
+               return true;
+
+       /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */
+       if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT)
+               new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+       /* make sure we got everything right */
+       FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+       FLAC__ASSERT(new_capacity > bw->capacity);
+       FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD));
+
+       new_buffer = (bwword*)safe_realloc_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity);
+       if(new_buffer == 0)
+               return false;
+       bw->buffer = new_buffer;
+       bw->capacity = new_capacity;
+       return true;
+}
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitWriter *FLAC__bitwriter_new(void)
+{
+       FLAC__BitWriter *bw = (FLAC__BitWriter*)calloc(1, sizeof(FLAC__BitWriter));
+       /* note that calloc() sets all members to 0 for us */
+       return bw;
+}
+
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw)
+{
+       FLAC__ASSERT(0 != bw);
+
+       FLAC__bitwriter_free(bw);
+       free(bw);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw)
+{
+       FLAC__ASSERT(0 != bw);
+
+       bw->words = bw->bits = 0;
+       bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY;
+       bw->buffer = (bwword*)malloc(sizeof(bwword) * bw->capacity);
+       if(bw->buffer == 0)
+               return false;
+
+       return true;
+}
+
+void FLAC__bitwriter_free(FLAC__BitWriter *bw)
+{
+       FLAC__ASSERT(0 != bw);
+
+       if(0 != bw->buffer)
+               free(bw->buffer);
+       bw->buffer = 0;
+       bw->capacity = 0;
+       bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw)
+{
+       bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out)
+{
+       unsigned i, j;
+       if(bw == 0) {
+               fprintf(out, "bitwriter is NULL\n");
+       }
+       else {
+               fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw));
+
+               for(i = 0; i < bw->words; i++) {
+                       fprintf(out, "%08X: ", i);
+                       for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+                               fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+                       fprintf(out, "\n");
+               }
+               if(bw->bits > 0) {
+                       fprintf(out, "%08X: ", i);
+                       for(j = 0; j < bw->bits; j++)
+                               fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0);
+                       fprintf(out, "\n");
+               }
+       }
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc)
+{
+       const FLAC__byte *buffer;
+       size_t bytes;
+
+       FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+       if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+               return false;
+
+       *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes);
+       FLAC__bitwriter_release_buffer(bw);
+       return true;
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc)
+{
+       const FLAC__byte *buffer;
+       size_t bytes;
+
+       FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+       if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+               return false;
+
+       *crc = FLAC__crc8(buffer, bytes);
+       FLAC__bitwriter_release_buffer(bw);
+       return true;
+}
+
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw)
+{
+       return ((bw->bits & 7) == 0);
+}
+
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw)
+{
+       return FLAC__TOTAL_BITS(bw);
+}
+
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes)
+{
+       FLAC__ASSERT((bw->bits & 7) == 0);
+       /* double protection */
+       if(bw->bits & 7)
+               return false;
+       /* if we have bits in the accumulator we have to flush those to the buffer first */
+       if(bw->bits) {
+               FLAC__ASSERT(bw->words <= bw->capacity);
+               if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD))
+                       return false;
+               /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */
+               bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits));
+       }
+       /* now we can just return what we have */
+       *buffer = (FLAC__byte*)bw->buffer;
+       *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3);
+       return true;
+}
+
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw)
+{
+       /* nothing to do.  in the future, strict checking of a 'writer-is-in-
+        * get-mode' flag could be added everywhere and then cleared here
+        */
+       (void)bw;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits)
+{
+       unsigned n;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+
+       if(bits == 0)
+               return true;
+       /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+       if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+               return false;
+       /* first part gets to word alignment */
+       if(bw->bits) {
+               n = min(FLAC__BITS_PER_WORD - bw->bits, bits);
+               bw->accum <<= n;
+               bits -= n;
+               bw->bits += n;
+               if(bw->bits == FLAC__BITS_PER_WORD) {
+                       bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+                       bw->bits = 0;
+               }
+               else
+                       return true;
+       }
+       /* do whole words */
+       while(bits >= FLAC__BITS_PER_WORD) {
+               bw->buffer[bw->words++] = 0;
+               bits -= FLAC__BITS_PER_WORD;
+       }
+       /* do any leftovers */
+       if(bits > 0) {
+               bw->accum = 0;
+               bw->bits = bits;
+       }
+       return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits)
+{
+       register unsigned left;
+
+       /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+       FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+
+       FLAC__ASSERT(bits <= 32);
+       if(bits == 0)
+               return true;
+
+       /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+       if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+               return false;
+
+       left = FLAC__BITS_PER_WORD - bw->bits;
+       if(bits < left) {
+               bw->accum <<= bits;
+               bw->accum |= val;
+               bw->bits += bits;
+       }
+       else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */
+               bw->accum <<= left;
+               bw->accum |= val >> (bw->bits = bits - left);
+               bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+               bw->accum = val;
+       }
+       else {
+               bw->accum = val;
+               bw->bits = 0;
+               bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val);
+       }
+
+       return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits)
+{
+       /* zero-out unused bits */
+       if(bits < 32)
+               val &= (~(0xffffffff << bits));
+
+       return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits)
+{
+       /* this could be a little faster but it's not used for much */
+       if(bits > 32) {
+               return
+                       FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) &&
+                       FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32);
+       }
+       else
+               return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+       /* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8))
+               return false;
+       if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8))
+               return false;
+       if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8))
+               return false;
+       if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8))
+               return false;
+
+       return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals)
+{
+       unsigned i;
+
+       /* this could be faster but currently we don't need it to be since it's only used for writing metadata */
+       for(i = 0; i < nvals; i++) {
+               if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8))
+                       return false;
+       }
+
+       return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val)
+{
+       if(val < 32)
+               return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val);
+       else
+               return
+                       FLAC__bitwriter_write_zeroes(bw, val) &&
+                       FLAC__bitwriter_write_raw_uint32(bw, 1, 1);
+}
+
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter)
+{
+       FLAC__uint32 uval;
+
+       FLAC__ASSERT(parameter < sizeof(unsigned)*8);
+
+       /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+       uval = (val<<1) ^ (val>>31);
+
+       return 1 + parameter + (uval >> parameter);
+}
+
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter)
+{
+       unsigned bits, msbs, uval;
+       unsigned k;
+
+       FLAC__ASSERT(parameter > 0);
+
+       /* fold signed to unsigned */
+       if(val < 0)
+               uval = (unsigned)(((-(++val)) << 1) + 1);
+       else
+               uval = (unsigned)(val << 1);
+
+       k = FLAC__bitmath_ilog2(parameter);
+       if(parameter == 1u<<k) {
+               FLAC__ASSERT(k <= 30);
+
+               msbs = uval >> k;
+               bits = 1 + k + msbs;
+       }
+       else {
+               unsigned q, r, d;
+
+               d = (1 << (k+1)) - parameter;
+               q = uval / parameter;
+               r = uval - (q * parameter);
+
+               bits = 1 + q + k;
+               if(r >= d)
+                       bits++;
+       }
+       return bits;
+}
+
+unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned uval, unsigned parameter)
+{
+       unsigned bits, msbs;
+       unsigned k;
+
+       FLAC__ASSERT(parameter > 0);
+
+       k = FLAC__bitmath_ilog2(parameter);
+       if(parameter == 1u<<k) {
+               FLAC__ASSERT(k <= 30);
+
+               msbs = uval >> k;
+               bits = 1 + k + msbs;
+       }
+       else {
+               unsigned q, r, d;
+
+               d = (1 << (k+1)) - parameter;
+               q = uval / parameter;
+               r = uval - (q * parameter);
+
+               bits = 1 + q + k;
+               if(r >= d)
+                       bits++;
+       }
+       return bits;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter)
+{
+       unsigned total_bits, interesting_bits, msbs;
+       FLAC__uint32 uval, pattern;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+       FLAC__ASSERT(parameter < 8*sizeof(uval));
+
+       /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+       uval = (val<<1) ^ (val>>31);
+
+       msbs = uval >> parameter;
+       interesting_bits = 1 + parameter;
+       total_bits = interesting_bits + msbs;
+       pattern = 1 << parameter; /* the unary end bit */
+       pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */
+
+       if(total_bits <= 32)
+               return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits);
+       else
+               return
+                       FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */
+                       FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */
+}
+
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter)
+{
+       const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */
+       const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/
+       FLAC__uint32 uval;
+       unsigned left;
+       const unsigned lsbits = 1 + parameter;
+       unsigned msbits;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+       FLAC__ASSERT(parameter < 8*sizeof(bwword)-1);
+       /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+       FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+       while(nvals) {
+               /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+               uval = (*vals<<1) ^ (*vals>>31);
+
+               msbits = uval >> parameter;
+
+#if 0 /* OPT: can remove this special case if it doesn't make up for the extra compare (doesn't make a statistically significant difference with msvc or gcc/x86) */
+               if(bw->bits && bw->bits + msbits + lsbits <= FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
+                       /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
+                       bw->bits = bw->bits + msbits + lsbits;
+                       uval |= mask1; /* set stop bit */
+                       uval &= mask2; /* mask off unused top bits */
+                       /* NOT: bw->accum <<= msbits + lsbits because msbits+lsbits could be 32, then the shift would be a NOP */
+                       bw->accum <<= msbits;
+                       bw->accum <<= lsbits;
+                       bw->accum |= uval;
+                       if(bw->bits == FLAC__BITS_PER_WORD) {
+                               bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+                               bw->bits = 0;
+                               /* burying the capacity check down here means we have to grow the buffer a little if there are more vals to do */
+                               if(bw->capacity <= bw->words && nvals > 1 && !bitwriter_grow_(bw, 1)) {
+                                       FLAC__ASSERT(bw->capacity == bw->words);
+                                       return false;
+                               }
+                       }
+               }
+               else {
+#elif 1 /*@@@@@@ OPT: try this version with MSVC6 to see if better, not much difference for gcc-4 */
+               if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
+                       /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
+                       bw->bits = bw->bits + msbits + lsbits;
+                       uval |= mask1; /* set stop bit */
+                       uval &= mask2; /* mask off unused top bits */
+                       bw->accum <<= msbits + lsbits;
+                       bw->accum |= uval;
+               }
+               else {
+#endif
+                       /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+                       /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */
+                       if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 bwword*/ && !bitwriter_grow_(bw, msbits+lsbits))
+                               return false;
+
+                       if(msbits) {
+                               /* first part gets to word alignment */
+                               if(bw->bits) {
+                                       left = FLAC__BITS_PER_WORD - bw->bits;
+                                       if(msbits < left) {
+                                               bw->accum <<= msbits;
+                                               bw->bits += msbits;
+                                               goto break1;
+                                       }
+                                       else {
+                                               bw->accum <<= left;
+                                               msbits -= left;
+                                               bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+                                               bw->bits = 0;
+                                       }
+                               }
+                               /* do whole words */
+                               while(msbits >= FLAC__BITS_PER_WORD) {
+                                       bw->buffer[bw->words++] = 0;
+                                       msbits -= FLAC__BITS_PER_WORD;
+                               }
+                               /* do any leftovers */
+                               if(msbits > 0) {
+                                       bw->accum = 0;
+                                       bw->bits = msbits;
+                               }
+                       }
+break1:
+                       uval |= mask1; /* set stop bit */
+                       uval &= mask2; /* mask off unused top bits */
+
+                       left = FLAC__BITS_PER_WORD - bw->bits;
+                       if(lsbits < left) {
+                               bw->accum <<= lsbits;
+                               bw->accum |= uval;
+                               bw->bits += lsbits;
+                       }
+                       else {
+                               /* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always
+                                * be > lsbits (because of previous assertions) so it would have
+                                * triggered the (lsbits<left) case above.
+                                */
+                               FLAC__ASSERT(bw->bits);
+                               FLAC__ASSERT(left < FLAC__BITS_PER_WORD);
+                               bw->accum <<= left;
+                               bw->accum |= uval >> (bw->bits = lsbits - left);
+                               bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+                               bw->accum = uval;
+                       }
+#if 1
+               }
+#endif
+               vals++;
+               nvals--;
+       }
+       return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter)
+{
+       unsigned total_bits, msbs, uval;
+       unsigned k;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+       FLAC__ASSERT(parameter > 0);
+
+       /* fold signed to unsigned */
+       if(val < 0)
+               uval = (unsigned)(((-(++val)) << 1) + 1);
+       else
+               uval = (unsigned)(val << 1);
+
+       k = FLAC__bitmath_ilog2(parameter);
+       if(parameter == 1u<<k) {
+               unsigned pattern;
+
+               FLAC__ASSERT(k <= 30);
+
+               msbs = uval >> k;
+               total_bits = 1 + k + msbs;
+               pattern = 1 << k; /* the unary end bit */
+               pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+               if(total_bits <= 32) {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+                               return false;
+               }
+               else {
+                       /* write the unary MSBs */
+                       if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+                               return false;
+                       /* write the unary end bit and binary LSBs */
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
+                               return false;
+               }
+       }
+       else {
+               unsigned q, r, d;
+
+               d = (1 << (k+1)) - parameter;
+               q = uval / parameter;
+               r = uval - (q * parameter);
+               /* write the unary MSBs */
+               if(!FLAC__bitwriter_write_zeroes(bw, q))
+                       return false;
+               /* write the unary end bit */
+               if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+                       return false;
+               /* write the binary LSBs */
+               if(r >= d) {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+                               return false;
+               }
+               else {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+                               return false;
+               }
+       }
+       return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter)
+{
+       unsigned total_bits, msbs;
+       unsigned k;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+       FLAC__ASSERT(parameter > 0);
+
+       k = FLAC__bitmath_ilog2(parameter);
+       if(parameter == 1u<<k) {
+               unsigned pattern;
+
+               FLAC__ASSERT(k <= 30);
+
+               msbs = uval >> k;
+               total_bits = 1 + k + msbs;
+               pattern = 1 << k; /* the unary end bit */
+               pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+               if(total_bits <= 32) {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+                               return false;
+               }
+               else {
+                       /* write the unary MSBs */
+                       if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+                               return false;
+                       /* write the unary end bit and binary LSBs */
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
+                               return false;
+               }
+       }
+       else {
+               unsigned q, r, d;
+
+               d = (1 << (k+1)) - parameter;
+               q = uval / parameter;
+               r = uval - (q * parameter);
+               /* write the unary MSBs */
+               if(!FLAC__bitwriter_write_zeroes(bw, q))
+                       return false;
+               /* write the unary end bit */
+               if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+                       return false;
+               /* write the binary LSBs */
+               if(r >= d) {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+                               return false;
+               }
+               else {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+                               return false;
+               }
+       }
+       return true;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+       FLAC__bool ok = 1;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+
+       FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */
+
+       if(val < 0x80) {
+               return FLAC__bitwriter_write_raw_uint32(bw, val, 8);
+       }
+       else if(val < 0x800) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+       }
+       else if(val < 0x10000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+       }
+       else if(val < 0x200000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+       }
+       else if(val < 0x4000000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+       }
+       else {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+       }
+
+       return ok;
+}
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val)
+{
+       FLAC__bool ok = 1;
+
+       FLAC__ASSERT(0 != bw);
+       FLAC__ASSERT(0 != bw->buffer);
+
+       FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */
+
+       if(val < 0x80) {
+               return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8);
+       }
+       else if(val < 0x800) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+       else if(val < 0x10000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+       else if(val < 0x200000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+       else if(val < 0x4000000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+       else if(val < 0x80000000) {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+       else {
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+               ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+       }
+
+       return ok;
+}
+
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw)
+{
+       /* 0-pad to byte boundary */
+       if(bw->bits & 7u)
+               return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u));
+       else
+               return true;
+}
diff --git a/src/libFLAC/cpu.c b/src/libFLAC/cpu.c
new file mode 100644 (file)
index 0000000..60b73bf
--- /dev/null
@@ -0,0 +1,418 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/cpu.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined FLAC__CPU_IA32
+# include <signal.h>
+#elif defined FLAC__CPU_PPC
+# if !defined FLAC__NO_ASM
+#  if defined FLAC__SYS_DARWIN
+#   include <sys/sysctl.h>
+#   include <mach/mach.h>
+#   include <mach/mach_host.h>
+#   include <mach/host_info.h>
+#   include <mach/machine.h>
+#   ifndef CPU_SUBTYPE_POWERPC_970
+#    define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
+#   endif
+#  else /* FLAC__SYS_DARWIN */
+
+#   include <signal.h>
+#   include <setjmp.h>
+
+static sigjmp_buf jmpbuf;
+static volatile sig_atomic_t canjump = 0;
+
+static void sigill_handler (int sig)
+{
+       if (!canjump) {
+               signal (sig, SIG_DFL);
+               raise (sig);
+       }
+       canjump = 0;
+       siglongjmp (jmpbuf, 1);
+}
+#  endif /* FLAC__SYS_DARWIN */
+# endif /* FLAC__NO_ASM */
+#endif /* FLAC__CPU_PPC */
+
+#if defined (__NetBSD__) || defined(__OpenBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <machine/cpu.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#if defined(__APPLE__)
+/* how to get sysctlbyname()? */
+#endif
+
+/* these are flags in EDX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
+/* these are flags in ECX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
+/* these are flags in EDX of CPUID AX=80000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
+
+
+/*
+ * Extra stuff needed for detection of OS support for SSE on IA-32
+ */
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS
+# if defined(__linux__)
+/*
+ * If the OS doesn't support SSE, we will get here with a SIGILL.  We
+ * modify the return address to jump over the offending SSE instruction
+ * and also the operation following it that indicates the instruction
+ * executed successfully.  In this way we use no global variables and
+ * stay thread-safe.
+ *
+ * 3 + 3 + 6:
+ *   3 bytes for "xorps xmm0,xmm0"
+ *   3 bytes for estimate of how long the follwing "inc var" instruction is
+ *   6 bytes extra in case our estimate is wrong
+ * 12 bytes puts us in the NOP "landing zone"
+ */
+#  undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */
+#  ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
+       static void sigill_handler_sse_os(int signal, struct sigcontext sc)
+       {
+               (void)signal;
+               sc.eip += 3 + 3 + 6;
+       }
+#  else
+#   include <sys/ucontext.h>
+       static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
+       {
+               (void)signal, (void)si;
+               ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
+       }
+#  endif
+# elif defined(_MSC_VER)
+#  include <windows.h>
+#  undef USE_TRY_CATCH_FLAVOR /* #define this to use the try/catch method for catching illegal opcode exception */
+#  ifdef USE_TRY_CATCH_FLAVOR
+#  else
+       LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
+       {
+               if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
+                       ep->ContextRecord->Eip += 3 + 3 + 6;
+                       return EXCEPTION_CONTINUE_EXECUTION;
+               }
+               return EXCEPTION_CONTINUE_SEARCH;
+       }
+#  endif
+# endif
+#endif
+
+
+void FLAC__cpu_info(FLAC__CPUInfo *info)
+{
+/*
+ * IA32-specific
+ */
+#ifdef FLAC__CPU_IA32
+       info->type = FLAC__CPUINFO_TYPE_IA32;
+#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+       info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
+       info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false;
+       info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */
+       info->data.ia32.cmov = false;
+       info->data.ia32.mmx = false;
+       info->data.ia32.fxsr = false;
+       info->data.ia32.sse = false;
+       info->data.ia32.sse2 = false;
+       info->data.ia32.sse3 = false;
+       info->data.ia32.ssse3 = false;
+       info->data.ia32._3dnow = false;
+       info->data.ia32.ext3dnow = false;
+       info->data.ia32.extmmx = false;
+       if(info->data.ia32.cpuid) {
+               /* http://www.sandpile.org/ia32/cpuid.htm */
+               FLAC__uint32 flags_edx, flags_ecx;
+               FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
+               info->data.ia32.cmov  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
+               info->data.ia32.mmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX  )? true : false;
+               info->data.ia32.fxsr  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
+               info->data.ia32.sse   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE  )? true : false;
+               info->data.ia32.sse2  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
+               info->data.ia32.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
+               info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
+
+#ifdef FLAC__USE_3DNOW
+               flags_edx = FLAC__cpu_info_extended_amd_asm_ia32();
+               info->data.ia32._3dnow   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW   )? true : false;
+               info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
+               info->data.ia32.extmmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX  )? true : false;
+#else
+               info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
+#endif
+
+#ifdef DEBUG
+               fprintf(stderr, "CPU info (IA-32):\n");
+               fprintf(stderr, "  CPUID ...... %c\n", info->data.ia32.cpuid   ? 'Y' : 'n');
+               fprintf(stderr, "  BSWAP ...... %c\n", info->data.ia32.bswap   ? 'Y' : 'n');
+               fprintf(stderr, "  CMOV ....... %c\n", info->data.ia32.cmov    ? 'Y' : 'n');
+               fprintf(stderr, "  MMX ........ %c\n", info->data.ia32.mmx     ? 'Y' : 'n');
+               fprintf(stderr, "  FXSR ....... %c\n", info->data.ia32.fxsr    ? 'Y' : 'n');
+               fprintf(stderr, "  SSE ........ %c\n", info->data.ia32.sse     ? 'Y' : 'n');
+               fprintf(stderr, "  SSE2 ....... %c\n", info->data.ia32.sse2    ? 'Y' : 'n');
+               fprintf(stderr, "  SSE3 ....... %c\n", info->data.ia32.sse3    ? 'Y' : 'n');
+               fprintf(stderr, "  SSSE3 ...... %c\n", info->data.ia32.ssse3   ? 'Y' : 'n');
+               fprintf(stderr, "  3DNow! ..... %c\n", info->data.ia32._3dnow  ? 'Y' : 'n');
+               fprintf(stderr, "  3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n');
+               fprintf(stderr, "  3DNow!-MMX . %c\n", info->data.ia32.extmmx  ? 'Y' : 'n');
+#endif
+
+               /*
+                * now have to check for OS support of SSE/SSE2
+                */
+               if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) {
+#if defined FLAC__NO_SSE_OS
+                       /* assume user knows better than us; turn it off */
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined FLAC__SSE_OS
+                       /* assume user knows better than us; leave as detected above */
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
+                       int sse = 0;
+                       size_t len;
+                       /* at least one of these must work: */
+                       len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
+                       len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse"   , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
+                       if(!sse)
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+# if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
+                       int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
+                       size_t len = sizeof(val);
+                       if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+                       else { /* double-check SSE2 */
+                               mib[1] = CPU_SSE2;
+                               len = sizeof(val);
+                               if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
+                                       info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+                       }
+# else
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+# endif
+#elif defined(__linux__)
+                       int sse = 0;
+                       struct sigaction sigill_save;
+#ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
+                       if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR)
+#else
+                       struct sigaction sigill_sse;
+                       sigill_sse.sa_sigaction = sigill_handler_sse_os;
+                       __sigemptyset(&sigill_sse.sa_mask);
+                       sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */
+                       if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
+#endif
+                       {
+                               /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
+                               /* see sigill_handler_sse_os() for an explanation of the following: */
+                               asm volatile (
+                                       "xorl %0,%0\n\t"          /* for some reason, still need to do this to clear 'sse' var */
+                                       "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
+                                       "incl %0\n\t"             /* SIGILL handler will jump over this */
+                                       /* landing zone */
+                                       "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
+                                       "nop\n\t"
+                                       "nop\n\t"
+                                       "nop\n\t"
+                                       "nop\n\t"
+                                       "nop\n\t"
+                                       "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
+                                       "nop\n\t"
+                                       "nop"     /* SIGILL jump lands here if "inc" is 1 byte */
+                                       : "=r"(sse)
+                                       : "r"(sse)
+                               );
+
+                               sigaction(SIGILL, &sigill_save, NULL);
+                       }
+
+                       if(!sse)
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined(_MSC_VER)
+# ifdef USE_TRY_CATCH_FLAVOR
+                       _try {
+                               __asm {
+#  if _MSC_VER <= 1200
+                                       /* VC6 assembler doesn't know SSE, have to emit bytecode instead */
+                                       _emit 0x0F
+                                       _emit 0x57
+                                       _emit 0xC0
+#  else
+                                       xorps xmm0,xmm0
+#  endif
+                               }
+                       }
+                       _except(EXCEPTION_EXECUTE_HANDLER) {
+                               if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
+                                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+                       }
+# else
+                       int sse = 0;
+                       LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
+                       /* see GCC version above for explanation */
+                       /*  http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx */
+                       /*  http://www.codeproject.com/cpp/gccasm.asp */
+                       /*  http://www.hick.org/~mmiller/msvc_inline_asm.html */
+                       __asm {
+#  if _MSC_VER <= 1200
+                               /* VC6 assembler doesn't know SSE, have to emit bytecode instead */
+                               _emit 0x0F
+                               _emit 0x57
+                               _emit 0xC0
+#  else
+                               xorps xmm0,xmm0
+#  endif
+                               inc sse
+                               nop
+                               nop
+                               nop
+                               nop
+                               nop
+                               nop
+                               nop
+                               nop
+                               nop
+                       }
+                       SetUnhandledExceptionFilter(save);
+                       if(!sse)
+                               info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+# endif
+#else
+                       /* no way to test, disable to be safe */
+                       info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#endif
+#ifdef DEBUG
+               fprintf(stderr, "  SSE OS sup . %c\n", info->data.ia32.sse     ? 'Y' : 'n');
+#endif
+
+               }
+       }
+#else
+       info->use_asm = false;
+#endif
+
+/*
+ * PPC-specific
+ */
+#elif defined FLAC__CPU_PPC
+       info->type = FLAC__CPUINFO_TYPE_PPC;
+# if !defined FLAC__NO_ASM
+       info->use_asm = true;
+#  ifdef FLAC__USE_ALTIVEC
+#   if defined FLAC__SYS_DARWIN
+       {
+               int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT };
+               size_t len = sizeof(val);
+               info->data.ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val);
+       }
+       {
+               host_basic_info_data_t hostInfo;
+               mach_msg_type_number_t infoCount;
+
+               infoCount = HOST_BASIC_INFO_COUNT;
+               host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
+
+               info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
+       }
+#   else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */
+       {
+               /* no Darwin, do it the brute-force way */
+               /* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */
+               info->data.ppc.altivec = 0;
+               info->data.ppc.ppc64 = 0;
+
+               signal (SIGILL, sigill_handler);
+               canjump = 0;
+               if (!sigsetjmp (jmpbuf, 1)) {
+                       canjump = 1;
+
+                       asm volatile (
+                               "mtspr 256, %0\n\t"
+                               "vand %%v0, %%v0, %%v0"
+                               :
+                               : "r" (-1)
+                       );
+
+                       info->data.ppc.altivec = 1;
+               }
+               canjump = 0;
+               if (!sigsetjmp (jmpbuf, 1)) {
+                       int x = 0;
+                       canjump = 1;
+
+                       /* PPC64 hardware implements the cntlzd instruction */
+                       asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) );
+
+                       info->data.ppc.ppc64 = 1;
+               }
+               signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */
+       }
+#   endif
+#  else /* !FLAC__USE_ALTIVEC */
+       info->data.ppc.altivec = 0;
+       info->data.ppc.ppc64 = 0;
+#  endif
+# else
+       info->use_asm = false;
+# endif
+
+/*
+ * unknown CPI
+ */
+#else
+       info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
+       info->use_asm = false;
+#endif
+}
diff --git a/src/libFLAC/crc.c b/src/libFLAC/crc.c
new file mode 100644 (file)
index 0000000..463ab65
--- /dev/null
@@ -0,0 +1,142 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__byte const FLAC__crc8_table[256] = {
+       0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+       0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+       0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+       0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+       0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+       0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+       0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+       0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+       0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+       0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+       0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+       0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+       0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+       0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+       0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+       0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+       0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+       0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+       0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+       0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+       0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+       0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+       0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+       0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+       0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+       0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+       0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+       0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+       0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+       0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+       0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+       0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+unsigned FLAC__crc16_table[256] = {
+       0x0000,  0x8005,  0x800f,  0x000a,  0x801b,  0x001e,  0x0014,  0x8011,
+       0x8033,  0x0036,  0x003c,  0x8039,  0x0028,  0x802d,  0x8027,  0x0022,
+       0x8063,  0x0066,  0x006c,  0x8069,  0x0078,  0x807d,  0x8077,  0x0072,
+       0x0050,  0x8055,  0x805f,  0x005a,  0x804b,  0x004e,  0x0044,  0x8041,
+       0x80c3,  0x00c6,  0x00cc,  0x80c9,  0x00d8,  0x80dd,  0x80d7,  0x00d2,
+       0x00f0,  0x80f5,  0x80ff,  0x00fa,  0x80eb,  0x00ee,  0x00e4,  0x80e1,
+       0x00a0,  0x80a5,  0x80af,  0x00aa,  0x80bb,  0x00be,  0x00b4,  0x80b1,
+       0x8093,  0x0096,  0x009c,  0x8099,  0x0088,  0x808d,  0x8087,  0x0082,
+       0x8183,  0x0186,  0x018c,  0x8189,  0x0198,  0x819d,  0x8197,  0x0192,
+       0x01b0,  0x81b5,  0x81bf,  0x01ba,  0x81ab,  0x01ae,  0x01a4,  0x81a1,
+       0x01e0,  0x81e5,  0x81ef,  0x01ea,  0x81fb,  0x01fe,  0x01f4,  0x81f1,
+       0x81d3,  0x01d6,  0x01dc,  0x81d9,  0x01c8,  0x81cd,  0x81c7,  0x01c2,
+       0x0140,  0x8145,  0x814f,  0x014a,  0x815b,  0x015e,  0x0154,  0x8151,
+       0x8173,  0x0176,  0x017c,  0x8179,  0x0168,  0x816d,  0x8167,  0x0162,
+       0x8123,  0x0126,  0x012c,  0x8129,  0x0138,  0x813d,  0x8137,  0x0132,
+       0x0110,  0x8115,  0x811f,  0x011a,  0x810b,  0x010e,  0x0104,  0x8101,
+       0x8303,  0x0306,  0x030c,  0x8309,  0x0318,  0x831d,  0x8317,  0x0312,
+       0x0330,  0x8335,  0x833f,  0x033a,  0x832b,  0x032e,  0x0324,  0x8321,
+       0x0360,  0x8365,  0x836f,  0x036a,  0x837b,  0x037e,  0x0374,  0x8371,
+       0x8353,  0x0356,  0x035c,  0x8359,  0x0348,  0x834d,  0x8347,  0x0342,
+       0x03c0,  0x83c5,  0x83cf,  0x03ca,  0x83db,  0x03de,  0x03d4,  0x83d1,
+       0x83f3,  0x03f6,  0x03fc,  0x83f9,  0x03e8,  0x83ed,  0x83e7,  0x03e2,
+       0x83a3,  0x03a6,  0x03ac,  0x83a9,  0x03b8,  0x83bd,  0x83b7,  0x03b2,
+       0x0390,  0x8395,  0x839f,  0x039a,  0x838b,  0x038e,  0x0384,  0x8381,
+       0x0280,  0x8285,  0x828f,  0x028a,  0x829b,  0x029e,  0x0294,  0x8291,
+       0x82b3,  0x02b6,  0x02bc,  0x82b9,  0x02a8,  0x82ad,  0x82a7,  0x02a2,
+       0x82e3,  0x02e6,  0x02ec,  0x82e9,  0x02f8,  0x82fd,  0x82f7,  0x02f2,
+       0x02d0,  0x82d5,  0x82df,  0x02da,  0x82cb,  0x02ce,  0x02c4,  0x82c1,
+       0x8243,  0x0246,  0x024c,  0x8249,  0x0258,  0x825d,  0x8257,  0x0252,
+       0x0270,  0x8275,  0x827f,  0x027a,  0x826b,  0x026e,  0x0264,  0x8261,
+       0x0220,  0x8225,  0x822f,  0x022a,  0x823b,  0x023e,  0x0234,  0x8231,
+       0x8213,  0x0216,  0x021c,  0x8219,  0x0208,  0x820d,  0x8207,  0x0202
+};
+
+
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc)
+{
+       *crc = FLAC__crc8_table[*crc ^ data];
+}
+
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc)
+{
+       while(len--)
+               *crc = FLAC__crc8_table[*crc ^ *data++];
+}
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len)
+{
+       FLAC__uint8 crc = 0;
+
+       while(len--)
+               crc = FLAC__crc8_table[crc ^ *data++];
+
+       return crc;
+}
+
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len)
+{
+       unsigned crc = 0;
+
+       while(len--)
+               crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff;
+
+       return crc;
+}
diff --git a/src/libFLAC/fixed.c b/src/libFLAC/fixed.c
new file mode 100644 (file)
index 0000000..1a3aac0
--- /dev/null
@@ -0,0 +1,435 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "FLAC/assert.h"
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x) < (y)? (x) : (y))
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((unsigned)((x)<0? -(x) : (x)))
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+/* rbps stands for residual bits per sample
+ *
+ *             (ln(2) * err)
+ * rbps = log  (-----------)
+ *           2 (     n     )
+ */
+static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n)
+{
+       FLAC__uint32 rbps;
+       unsigned bits; /* the number of bits required to represent a number */
+       int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+       FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+       FLAC__ASSERT(err > 0);
+       FLAC__ASSERT(n > 0);
+
+       FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+       if(err <= n)
+               return 0;
+       /*
+        * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+        * These allow us later to know we won't lose too much precision in the
+        * fixed-point division (err<<fracbits)/n.
+        */
+
+       fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1);
+
+       err <<= fracbits;
+       err /= n;
+       /* err now holds err/n with fracbits fractional bits */
+
+       /*
+        * Whittle err down to 16 bits max.  16 significant bits is enough for
+        * our purposes.
+        */
+       FLAC__ASSERT(err > 0);
+       bits = FLAC__bitmath_ilog2(err)+1;
+       if(bits > 16) {
+               err >>= (bits-16);
+               fracbits -= (bits-16);
+       }
+       rbps = (FLAC__uint32)err;
+
+       /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+       rbps *= FLAC__FP_LN2;
+       fracbits += 16;
+       FLAC__ASSERT(fracbits >= 0);
+
+       /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+       {
+               const int f = fracbits & 3;
+               if(f) {
+                       rbps >>= f;
+                       fracbits -= f;
+               }
+       }
+
+       rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+       if(rbps == 0)
+               return 0;
+
+       /*
+        * The return value must have 16 fractional bits.  Since the whole part
+        * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+        * must be >= -3, these assertion allows us to be able to shift rbps
+        * left if necessary to get 16 fracbits without losing any bits of the
+        * whole part of rbps.
+        *
+        * There is a slight chance due to accumulated error that the whole part
+        * will require 6 bits, so we use 6 in the assertion.  Really though as
+        * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+        */
+       FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+       FLAC__ASSERT(fracbits >= -3);
+
+       /* now shift the decimal point into place */
+       if(fracbits < 16)
+               return rbps << (16-fracbits);
+       else if(fracbits > 16)
+               return rbps >> (fracbits-16);
+       else
+               return rbps;
+}
+
+static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n)
+{
+       FLAC__uint32 rbps;
+       unsigned bits; /* the number of bits required to represent a number */
+       int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+       FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+       FLAC__ASSERT(err > 0);
+       FLAC__ASSERT(n > 0);
+
+       FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+       if(err <= n)
+               return 0;
+       /*
+        * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+        * These allow us later to know we won't lose too much precision in the
+        * fixed-point division (err<<fracbits)/n.
+        */
+
+       fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1);
+
+       err <<= fracbits;
+       err /= n;
+       /* err now holds err/n with fracbits fractional bits */
+
+       /*
+        * Whittle err down to 16 bits max.  16 significant bits is enough for
+        * our purposes.
+        */
+       FLAC__ASSERT(err > 0);
+       bits = FLAC__bitmath_ilog2_wide(err)+1;
+       if(bits > 16) {
+               err >>= (bits-16);
+               fracbits -= (bits-16);
+       }
+       rbps = (FLAC__uint32)err;
+
+       /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+       rbps *= FLAC__FP_LN2;
+       fracbits += 16;
+       FLAC__ASSERT(fracbits >= 0);
+
+       /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+       {
+               const int f = fracbits & 3;
+               if(f) {
+                       rbps >>= f;
+                       fracbits -= f;
+               }
+       }
+
+       rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+       if(rbps == 0)
+               return 0;
+
+       /*
+        * The return value must have 16 fractional bits.  Since the whole part
+        * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+        * must be >= -3, these assertion allows us to be able to shift rbps
+        * left if necessary to get 16 fracbits without losing any bits of the
+        * whole part of rbps.
+        *
+        * There is a slight chance due to accumulated error that the whole part
+        * will require 6 bits, so we use 6 in the assertion.  Really though as
+        * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+        */
+       FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+       FLAC__ASSERT(fracbits >= -3);
+
+       /* now shift the decimal point into place */
+       if(fracbits < 16)
+               return rbps << (16-fracbits);
+       else if(fracbits > 16)
+               return rbps >> (fracbits-16);
+       else
+               return rbps;
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+       FLAC__int32 last_error_0 = data[-1];
+       FLAC__int32 last_error_1 = data[-1] - data[-2];
+       FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+       FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+       FLAC__int32 error, save;
+       FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+       unsigned i, order;
+
+       for(i = 0; i < data_len; i++) {
+               error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+               error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+               error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+               error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+               error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+       }
+
+       if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+               order = 0;
+       else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+               order = 1;
+       else if(total_error_2 < min(total_error_3, total_error_4))
+               order = 2;
+       else if(total_error_3 < total_error_4)
+               order = 3;
+       else
+               order = 4;
+
+       /* Estimate the expected number of bits per residual signal sample. */
+       /* 'total_error*' is linearly related to the variance of the residual */
+       /* signal, so we use it directly to compute E(|x|) */
+       FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#else
+       residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0;
+       residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0;
+       residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0;
+       residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0;
+       residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0;
+#endif
+
+       return order;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+       FLAC__int32 last_error_0 = data[-1];
+       FLAC__int32 last_error_1 = data[-1] - data[-2];
+       FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+       FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+       FLAC__int32 error, save;
+       /* total_error_* are 64-bits to avoid overflow when encoding
+        * erratic signals when the bits-per-sample and blocksize are
+        * large.
+        */
+       FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+       unsigned i, order;
+
+       for(i = 0; i < data_len; i++) {
+               error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+               error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+               error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+               error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+               error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+       }
+
+       if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+               order = 0;
+       else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+               order = 1;
+       else if(total_error_2 < min(total_error_3, total_error_4))
+               order = 2;
+       else if(total_error_3 < total_error_4)
+               order = 3;
+       else
+               order = 4;
+
+       /* Estimate the expected number of bits per residual signal sample. */
+       /* 'total_error*' is linearly related to the variance of the residual */
+       /* signal, so we use it directly to compute E(|x|) */
+       FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+       FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+       /* with MSVC you have to spoon feed it the casting */
+       residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#else
+       residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#endif
+#else
+       residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0;
+       residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0;
+       residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0;
+       residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0;
+       residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0;
+#endif
+
+       return order;
+}
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
+{
+       const int idata_len = (int)data_len;
+       int i;
+
+       switch(order) {
+               case 0:
+                       FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+                       memcpy(residual, data, sizeof(residual[0])*data_len);
+                       break;
+               case 1:
+                       for(i = 0; i < idata_len; i++)
+                               residual[i] = data[i] - data[i-1];
+                       break;
+               case 2:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
+#else
+                               residual[i] = data[i] - 2*data[i-1] + data[i-2];
+#endif
+                       break;
+               case 3:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
+#else
+                               residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+#endif
+                       break;
+               case 4:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
+#else
+                               residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+#endif
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[])
+{
+       int i, idata_len = (int)data_len;
+
+       switch(order) {
+               case 0:
+                       FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+                       memcpy(data, residual, sizeof(residual[0])*data_len);
+                       break;
+               case 1:
+                       for(i = 0; i < idata_len; i++)
+                               data[i] = residual[i] + data[i-1];
+                       break;
+               case 2:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               data[i] = residual[i] + (data[i-1]<<1) - data[i-2];
+#else
+                               data[i] = residual[i] + 2*data[i-1] - data[i-2];
+#endif
+                       break;
+               case 3:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3];
+#else
+                               data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+#endif
+                       break;
+               case 4:
+                       for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+                               data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4];
+#else
+                               data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+#endif
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+}
diff --git a/src/libFLAC/flac.pc.in b/src/libFLAC/flac.pc.in
new file mode 100644 (file)
index 0000000..8fc39f8
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC
+Description: Free Lossless Audio Codec Library
+Version: @VERSION@
+Libs: -L${libdir} -lFLAC -lm
+Cflags: -I${includedir}/FLAC
diff --git a/src/libFLAC/float.c b/src/libFLAC/float.c
new file mode 100644 (file)
index 0000000..8e19280
--- /dev/null
@@ -0,0 +1,308 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+
+#include "private/float.h"
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+const FLAC__fixedpoint FLAC__FP_ZERO = 0;
+const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000;
+const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000;
+const FLAC__fixedpoint FLAC__FP_LN2 = 45426;
+const FLAC__fixedpoint FLAC__FP_E = 178145;
+
+/* Lookup tables for Knuth's logarithm algorithm */
+#define LOG2_LOOKUP_PRECISION 16
+static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = {
+       {
+               /*
+                * 0 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00000001,
+               /* lg(4/3) = */ 0x00000000,
+               /* lg(8/7) = */ 0x00000000,
+               /* lg(16/15) = */ 0x00000000,
+               /* lg(32/31) = */ 0x00000000,
+               /* lg(64/63) = */ 0x00000000,
+               /* lg(128/127) = */ 0x00000000,
+               /* lg(256/255) = */ 0x00000000,
+               /* lg(512/511) = */ 0x00000000,
+               /* lg(1024/1023) = */ 0x00000000,
+               /* lg(2048/2047) = */ 0x00000000,
+               /* lg(4096/4095) = */ 0x00000000,
+               /* lg(8192/8191) = */ 0x00000000,
+               /* lg(16384/16383) = */ 0x00000000,
+               /* lg(32768/32767) = */ 0x00000000
+       },
+       {
+               /*
+                * 4 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00000010,
+               /* lg(4/3) = */ 0x00000007,
+               /* lg(8/7) = */ 0x00000003,
+               /* lg(16/15) = */ 0x00000001,
+               /* lg(32/31) = */ 0x00000001,
+               /* lg(64/63) = */ 0x00000000,
+               /* lg(128/127) = */ 0x00000000,
+               /* lg(256/255) = */ 0x00000000,
+               /* lg(512/511) = */ 0x00000000,
+               /* lg(1024/1023) = */ 0x00000000,
+               /* lg(2048/2047) = */ 0x00000000,
+               /* lg(4096/4095) = */ 0x00000000,
+               /* lg(8192/8191) = */ 0x00000000,
+               /* lg(16384/16383) = */ 0x00000000,
+               /* lg(32768/32767) = */ 0x00000000
+       },
+       {
+               /*
+                * 8 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00000100,
+               /* lg(4/3) = */ 0x0000006a,
+               /* lg(8/7) = */ 0x00000031,
+               /* lg(16/15) = */ 0x00000018,
+               /* lg(32/31) = */ 0x0000000c,
+               /* lg(64/63) = */ 0x00000006,
+               /* lg(128/127) = */ 0x00000003,
+               /* lg(256/255) = */ 0x00000001,
+               /* lg(512/511) = */ 0x00000001,
+               /* lg(1024/1023) = */ 0x00000000,
+               /* lg(2048/2047) = */ 0x00000000,
+               /* lg(4096/4095) = */ 0x00000000,
+               /* lg(8192/8191) = */ 0x00000000,
+               /* lg(16384/16383) = */ 0x00000000,
+               /* lg(32768/32767) = */ 0x00000000
+       },
+       {
+               /*
+                * 12 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00001000,
+               /* lg(4/3) = */ 0x000006a4,
+               /* lg(8/7) = */ 0x00000315,
+               /* lg(16/15) = */ 0x0000017d,
+               /* lg(32/31) = */ 0x000000bc,
+               /* lg(64/63) = */ 0x0000005d,
+               /* lg(128/127) = */ 0x0000002e,
+               /* lg(256/255) = */ 0x00000017,
+               /* lg(512/511) = */ 0x0000000c,
+               /* lg(1024/1023) = */ 0x00000006,
+               /* lg(2048/2047) = */ 0x00000003,
+               /* lg(4096/4095) = */ 0x00000001,
+               /* lg(8192/8191) = */ 0x00000001,
+               /* lg(16384/16383) = */ 0x00000000,
+               /* lg(32768/32767) = */ 0x00000000
+       },
+       {
+               /*
+                * 16 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00010000,
+               /* lg(4/3) = */ 0x00006a40,
+               /* lg(8/7) = */ 0x00003151,
+               /* lg(16/15) = */ 0x000017d6,
+               /* lg(32/31) = */ 0x00000bba,
+               /* lg(64/63) = */ 0x000005d1,
+               /* lg(128/127) = */ 0x000002e6,
+               /* lg(256/255) = */ 0x00000172,
+               /* lg(512/511) = */ 0x000000b9,
+               /* lg(1024/1023) = */ 0x0000005c,
+               /* lg(2048/2047) = */ 0x0000002e,
+               /* lg(4096/4095) = */ 0x00000017,
+               /* lg(8192/8191) = */ 0x0000000c,
+               /* lg(16384/16383) = */ 0x00000006,
+               /* lg(32768/32767) = */ 0x00000003
+       },
+       {
+               /*
+                * 20 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x00100000,
+               /* lg(4/3) = */ 0x0006a3fe,
+               /* lg(8/7) = */ 0x00031513,
+               /* lg(16/15) = */ 0x00017d60,
+               /* lg(32/31) = */ 0x0000bb9d,
+               /* lg(64/63) = */ 0x00005d10,
+               /* lg(128/127) = */ 0x00002e59,
+               /* lg(256/255) = */ 0x00001721,
+               /* lg(512/511) = */ 0x00000b8e,
+               /* lg(1024/1023) = */ 0x000005c6,
+               /* lg(2048/2047) = */ 0x000002e3,
+               /* lg(4096/4095) = */ 0x00000171,
+               /* lg(8192/8191) = */ 0x000000b9,
+               /* lg(16384/16383) = */ 0x0000005c,
+               /* lg(32768/32767) = */ 0x0000002e
+       },
+       {
+               /*
+                * 24 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x01000000,
+               /* lg(4/3) = */ 0x006a3fe6,
+               /* lg(8/7) = */ 0x00315130,
+               /* lg(16/15) = */ 0x0017d605,
+               /* lg(32/31) = */ 0x000bb9ca,
+               /* lg(64/63) = */ 0x0005d0fc,
+               /* lg(128/127) = */ 0x0002e58f,
+               /* lg(256/255) = */ 0x0001720e,
+               /* lg(512/511) = */ 0x0000b8d8,
+               /* lg(1024/1023) = */ 0x00005c61,
+               /* lg(2048/2047) = */ 0x00002e2d,
+               /* lg(4096/4095) = */ 0x00001716,
+               /* lg(8192/8191) = */ 0x00000b8b,
+               /* lg(16384/16383) = */ 0x000005c5,
+               /* lg(32768/32767) = */ 0x000002e3
+       },
+       {
+               /*
+                * 28 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ 0x10000000,
+               /* lg(4/3) = */ 0x06a3fe5c,
+               /* lg(8/7) = */ 0x03151301,
+               /* lg(16/15) = */ 0x017d6049,
+               /* lg(32/31) = */ 0x00bb9ca6,
+               /* lg(64/63) = */ 0x005d0fba,
+               /* lg(128/127) = */ 0x002e58f7,
+               /* lg(256/255) = */ 0x001720da,
+               /* lg(512/511) = */ 0x000b8d87,
+               /* lg(1024/1023) = */ 0x0005c60b,
+               /* lg(2048/2047) = */ 0x0002e2d7,
+               /* lg(4096/4095) = */ 0x00017160,
+               /* lg(8192/8191) = */ 0x0000b8ad,
+               /* lg(16384/16383) = */ 0x00005c56,
+               /* lg(32768/32767) = */ 0x00002e2b
+       }
+};
+
+#if 0
+static const FLAC__uint64 log2_lookup_wide[] = {
+       {
+               /*
+                * 32 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ FLAC__U64L(0x100000000),
+               /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6),
+               /* lg(8/7) = */ FLAC__U64L(0x31513015),
+               /* lg(16/15) = */ FLAC__U64L(0x17d60497),
+               /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65),
+               /* lg(64/63) = */ FLAC__U64L(0x05d0fba2),
+               /* lg(128/127) = */ FLAC__U64L(0x02e58f74),
+               /* lg(256/255) = */ FLAC__U64L(0x01720d9c),
+               /* lg(512/511) = */ FLAC__U64L(0x00b8d875),
+               /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa),
+               /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72),
+               /* lg(4096/4095) = */ FLAC__U64L(0x00171600),
+               /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2),
+               /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d),
+               /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac)
+       },
+       {
+               /*
+                * 48 fraction bits
+                */
+               /* undefined */ 0x00000000,
+               /* lg(2/1) = */ FLAC__U64L(0x1000000000000),
+               /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429),
+               /* lg(8/7) = */ FLAC__U64L(0x315130157f7a),
+               /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb),
+               /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac),
+               /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd),
+               /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee),
+               /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8),
+               /* lg(512/511) = */ FLAC__U64L(0xb8d8752173),
+               /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e),
+               /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8),
+               /* lg(4096/4095) = */ FLAC__U64L(0x1716001719),
+               /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b),
+               /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d),
+               /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52)
+       }
+};
+#endif
+
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision)
+{
+       const FLAC__uint32 ONE = (1u << fracbits);
+       const FLAC__uint32 *table = log2_lookup[fracbits >> 2];
+
+       FLAC__ASSERT(fracbits < 32);
+       FLAC__ASSERT((fracbits & 0x3) == 0);
+
+       if(x < ONE)
+               return 0;
+       
+       if(precision > LOG2_LOOKUP_PRECISION)
+               precision = LOG2_LOOKUP_PRECISION;
+
+       /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */
+       {
+               FLAC__uint32 y = 0;
+               FLAC__uint32 z = x >> 1, k = 1;
+               while (x > ONE && k < precision) {
+                       if (x - z >= ONE) {
+                               x -= z;
+                               z = x >> k;
+                               y += table[k];
+                       }
+                       else {
+                               z >>= 1;
+                               k++;
+                       }
+               }
+               return y;
+       }
+}
+
+#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c
new file mode 100644 (file)
index 0000000..749461d
--- /dev/null
@@ -0,0 +1,593 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for memset() */
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/format.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/* VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = VERSION;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__
+/* yet one more hack because of MSVC6: */
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.2.1 20070917";
+#else
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070917";
+#endif
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
+       "PARTITIONED_RICE",
+       "PARTITIONED_RICE2"
+};
+
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+       "CONSTANT",
+       "VERBATIM",
+       "FIXED",
+       "LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+       "INDEPENDENT",
+       "LEFT_SIDE",
+       "RIGHT_SIDE",
+       "MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+       "FRAME_NUMBER_TYPE_FRAME_NUMBER",
+       "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+       "STREAMINFO",
+       "PADDING",
+       "APPLICATION",
+       "SEEKTABLE",
+       "VORBIS_COMMENT",
+       "CUESHEET",
+       "PICTURE"
+};
+
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+       "Other",
+       "32x32 pixels 'file icon' (PNG only)",
+       "Other file icon",
+       "Cover (front)",
+       "Cover (back)",
+       "Leaflet page",
+       "Media (e.g. label side of CD)",
+       "Lead artist/lead performer/soloist",
+       "Artist/performer",
+       "Conductor",
+       "Band/Orchestra",
+       "Composer",
+       "Lyricist/text writer",
+       "Recording Location",
+       "During recording",
+       "During performance",
+       "Movie/video screen capture",
+       "A bright coloured fish",
+       "Illustration",
+       "Band/artist logotype",
+       "Publisher/Studio logotype"
+};
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
+{
+       if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
+               return false;
+       }
+       else
+               return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate)
+{
+       if(
+               !FLAC__format_sample_rate_is_valid(sample_rate) ||
+               (
+                       sample_rate >= (1u << 16) &&
+                       !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+               )
+       ) {
+               return false;
+       }
+       else
+               return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
+{
+       unsigned i;
+       FLAC__uint64 prev_sample_number = 0;
+       FLAC__bool got_prev = false;
+
+       FLAC__ASSERT(0 != seek_table);
+
+       for(i = 0; i < seek_table->num_points; i++) {
+               if(got_prev) {
+                       if(
+                               seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+                               seek_table->points[i].sample_number <= prev_sample_number
+                       )
+                               return false;
+               }
+               prev_sample_number = seek_table->points[i].sample_number;
+               got_prev = true;
+       }
+
+       return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+       /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+       if(l->sample_number == r->sample_number)
+               return 0;
+       else if(l->sample_number < r->sample_number)
+               return -1;
+       else
+               return 1;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+       unsigned i, j;
+       FLAC__bool first;
+
+       FLAC__ASSERT(0 != seek_table);
+
+       /* sort the seekpoints */
+       qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+       /* uniquify the seekpoints */
+       first = true;
+       for(i = j = 0; i < seek_table->num_points; i++) {
+               if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+                       if(!first) {
+                               if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+                                       continue;
+                       }
+               }
+               first = false;
+               seek_table->points[j++] = seek_table->points[i];
+       }
+
+       for(i = j; i < seek_table->num_points; i++) {
+               seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+               seek_table->points[i].stream_offset = 0;
+               seek_table->points[i].frame_samples = 0;
+       }
+
+       return j;
+}
+
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ *   http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ *   http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static FLaC__INLINE unsigned utf8len_(const FLAC__byte *utf8)
+{
+       FLAC__ASSERT(0 != utf8);
+       if ((utf8[0] & 0x80) == 0) {
+               return 1;
+       }
+       else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+               if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+                       return 0;
+               return 2;
+       }
+       else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+                       return 0;
+               /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+               if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+                       return 0;
+               if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+                       return 0;
+               return 3;
+       }
+       else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 4;
+       }
+       else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 5;
+       }
+       else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 6;
+       }
+       else {
+               return 0;
+       }
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
+{
+       char c;
+       for(c = *name; c; c = *(++name))
+               if(c < 0x20 || c == 0x3d || c > 0x7d)
+                       return false;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
+{
+       if(length == (unsigned)(-1)) {
+               while(*value) {
+                       unsigned n = utf8len_(value);
+                       if(n == 0)
+                               return false;
+                       value += n;
+               }
+       }
+       else {
+               const FLAC__byte *end = value + length;
+               while(value < end) {
+                       unsigned n = utf8len_(value);
+                       if(n == 0)
+                               return false;
+                       value += n;
+               }
+               if(value != end)
+                       return false;
+       }
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
+{
+       const FLAC__byte *s, *end;
+
+       for(s = entry, end = s + length; s < end && *s != '='; s++) {
+               if(*s < 0x20 || *s > 0x7D)
+                       return false;
+       }
+       if(s == end)
+               return false;
+
+       s++; /* skip '=' */
+
+       while(s < end) {
+               unsigned n = utf8len_(s);
+               if(n == 0)
+                       return false;
+               s += n;
+       }
+       if(s != end)
+               return false;
+
+       return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+       unsigned i, j;
+
+       if(check_cd_da_subset) {
+               if(cue_sheet->lead_in < 2 * 44100) {
+                       if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+                       return false;
+               }
+               if(cue_sheet->lead_in % 588 != 0) {
+                       if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+                       return false;
+               }
+       }
+
+       if(cue_sheet->num_tracks == 0) {
+               if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+               return false;
+       }
+
+       if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+               if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+               return false;
+       }
+
+       for(i = 0; i < cue_sheet->num_tracks; i++) {
+               if(cue_sheet->tracks[i].number == 0) {
+                       if(violation) *violation = "cue sheet may not have a track number 0";
+                       return false;
+               }
+
+               if(check_cd_da_subset) {
+                       if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+                               if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+                               return false;
+                       }
+               }
+
+               if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+                       if(violation) {
+                               if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
+                                       *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
+                               else
+                                       *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+                       }
+                       return false;
+               }
+
+               if(i < cue_sheet->num_tracks - 1) {
+                       if(cue_sheet->tracks[i].num_indices == 0) {
+                               if(violation) *violation = "cue sheet track must have at least one index point";
+                               return false;
+                       }
+
+                       if(cue_sheet->tracks[i].indices[0].number > 1) {
+                               if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+                               return false;
+                       }
+               }
+
+               for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+                       if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+                               if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+                               return false;
+                       }
+
+                       if(j > 0) {
+                               if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+                                       if(violation) *violation = "cue sheet track index numbers must increase by 1";
+                                       return false;
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+       char *p;
+       FLAC__byte *b;
+
+       for(p = picture->mime_type; *p; p++) {
+               if(*p < 0x20 || *p > 0x7e) {
+                       if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+                       return false;
+               }
+       }
+
+       for(b = picture->description; *b; ) {
+               unsigned n = utf8len_(b);
+               if(n == 0) {
+                       if(violation) *violation = "description string must be valid UTF-8";
+                       return false;
+               }
+               b += n;
+       }
+
+       return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
+{
+       return
+               FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+                       FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+                       blocksize,
+                       predictor_order
+               );
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
+{
+       unsigned max_rice_partition_order = 0;
+       while(!(blocksize & 1)) {
+               max_rice_partition_order++;
+               blocksize >>= 1;
+       }
+       return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
+{
+       unsigned max_rice_partition_order = limit;
+
+       while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+               max_rice_partition_order--;
+
+       FLAC__ASSERT(
+               (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
+               (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
+       );
+
+       return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+       FLAC__ASSERT(0 != object);
+
+       object->parameters = 0;
+       object->raw_bits = 0;
+       object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+       FLAC__ASSERT(0 != object);
+
+       if(0 != object->parameters)
+               free(object->parameters);
+       if(0 != object->raw_bits)
+               free(object->raw_bits);
+       FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
+{
+       FLAC__ASSERT(0 != object);
+
+       FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
+
+       if(object->capacity_by_order < max_partition_order) {
+               if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
+                       return false;
+               if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
+                       return false;
+               memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order));
+               object->capacity_by_order = max_partition_order;
+       }
+
+       return true;
+}
diff --git a/src/libFLAC/ia32/Makefile.am b/src/libFLAC/ia32/Makefile.am
new file mode 100644 (file)
index 0000000..04a5b98
--- /dev/null
@@ -0,0 +1,45 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SUFFIXES = .nasm .lo
+
+STRIP_NON_ASM = sh $(top_srcdir)/strip_non_asm_libtool_args.sh
+
+.nasm.lo:
+       $(LIBTOOL) --tag=CC --mode=compile $(STRIP_NON_ASM) $(NASM) -f $(OBJ_FORMAT) -d OBJ_FORMAT_$(OBJ_FORMAT) -i$(srcdir)/ $< -o $@
+
+noinst_LTLIBRARIES = libFLAC-asm.la
+libFLAC_asm_la_SOURCES = \
+       bitreader_asm.nasm \
+       cpu_asm.nasm \
+       fixed_asm.nasm \
+       lpc_asm.nasm \
+       nasm.h \
+       stream_encoder_asm.nasm
diff --git a/src/libFLAC/ia32/bitreader_asm.nasm b/src/libFLAC/ia32/bitreader_asm.nasm
new file mode 100644 (file)
index 0000000..5d1bbfa
--- /dev/null
@@ -0,0 +1,568 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+       data_section
+
+cextern FLAC__crc16_table              ; unsigned FLAC__crc16_table[256];
+cextern bitreader_read_from_client_    ; FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
+
+cglobal FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+       code_section
+
+
+; **********************************************************************
+;
+; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+;
+; Some details like assertions and other checking is performed by the caller.
+       ALIGN 16
+cident FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+       ;ASSERT(0 != br);
+       ;ASSERT(0 != br->buffer);
+       ; WATCHOUT: code only works if sizeof(brword)==32; we can make things much faster with this assertion
+       ;ASSERT(FLAC__BITS_PER_WORD == 32);
+       ;ASSERT(parameter < 32);
+       ; the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it
+
+       ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
+       ;; [esp + 16]   unsigned parameter
+       ;; [esp + 12]   unsigned nvals
+       ;; [esp + 8]    int vals[]
+       ;; [esp + 4]    FLAC__BitReader *br
+       mov     eax, [esp + 12]         ; if(nvals == 0)
+       test    eax, eax
+       ja      .nvals_gt_0
+       mov     eax, 1                  ;   return true;
+       ret
+
+.nvals_gt_0:
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+       sub     esp, 4
+       ;; [esp + 36]   unsigned parameter
+       ;; [esp + 32]   unsigned nvals
+       ;; [esp + 28]   int vals[]
+       ;; [esp + 24]   FLAC__BitReader *br
+       ;; [esp]        ucbits
+       mov     ebp, [esp + 24]         ; ebp <- br == br->buffer
+       mov     esi, [ebp + 16]         ; esi <- br->consumed_words (aka 'cwords' in the C version)
+       mov     ecx, [ebp + 20]         ; ecx <- br->consumed_bits  (aka 'cbits'  in the C version)
+       xor     edi, edi                ; edi <- 0  'uval'
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       ;; [ebp]        br->buffer
+       ;; [ebp + 8]    br->words
+       ;; [ebp + 12]   br->bytes
+       ;; [ebp + 16]   br->consumed_words
+       ;; [ebp + 20]   br->consumed_bits
+       ;; [ebp + 24]   br->read_crc
+       ;; [ebp + 28]   br->crc16_align
+
+                                       ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+       mov     eax, [ebp + 8]          ;   eax <- br->words
+       sub     eax, esi                ;   eax <- br->words-cwords
+       shl     eax, 2                  ;   eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+       add     eax, [ebp + 12]         ;   eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+       shl     eax, 3                  ;   eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+       sub     eax, ecx                ;   eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+       mov     [esp], eax              ;   ucbits <- eax
+
+       ALIGN 16
+.val_loop:                             ; while(1) {
+
+       ;
+       ; read unary part
+       ;
+.unary_loop:                           ;   while(1) {
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       cmp     esi, [ebp + 8]          ;     while(cwords < br->words)   /* if we've not consumed up to a partial tail word... */
+       jae     near .c1_next1
+.c1_loop:                              ;     {
+       mov     ebx, [ebp]
+       mov     eax, [ebx + 4*esi]      ;       b = br->buffer[cwords]
+       mov     edx, eax                ;       edx = br->buffer[cwords] (saved for later use)
+       shl     eax, cl                 ;       b = br->buffer[cwords] << cbits
+       test    eax, eax                ;         (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+       jz      near .c1_next2          ;       if(b) {
+       bsr     ebx, eax
+       not     ebx
+       and     ebx, 31                 ;         ebx = 'i' = # of leading 0 bits in 'b' (eax)
+       add     ecx, ebx                ;         cbits += i;
+       add     edi, ebx                ;         uval += i;
+       add     ecx, byte 1             ;         cbits++; /* skip over stop bit */
+       test    ecx, ~31
+       jz      near .break1            ;         if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
+                                       ;           crc16_update_word_(br, br->buffer[cwords]);
+       push    edi                     ;               [need more registers]
+       bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+       mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
+       mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+       mov     edi, _FLAC__crc16_table
+%else
+       mov     edi, FLAC__crc16_table
+%endif
+       ;; eax (ax)     crc a.k.a. br->read_crc
+       ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
+       ;; ecx          br->crc16_align
+       ;; edx          byteswapped brword to CRC
+       ;; esi          cwords
+       ;; edi          unsigned FLAC__crc16_table[]
+       ;; ebp          br
+       test    ecx, ecx                ;               switch(br->crc16_align) ...
+       jnz     .c0b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c0b0: xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c0b1: xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shr     edx, 16
+.c0b2: xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c0b3: xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       movzx   eax, ax
+       mov     [ebp + 24], eax         ;               br->read_crc <- crc
+       pop     edi
+
+       add     esi, byte 1             ;           cwords++;
+       xor     ecx, ecx                ;           cbits = 0;
+                                       ;         }
+       jmp     near .break1            ;         goto break1;
+       ;; this section relocated out of the way for performance
+.c0b4:
+       mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
+       cmp     ecx, 8
+       je      .c0b1
+       shr     edx, 16
+       cmp     ecx, 16
+       je      .c0b2
+       jmp     .c0b3
+
+       ;; this section relocated out of the way for performance
+.c1b4:
+       mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
+       cmp     ecx, 8
+       je      .c1b1
+       shr     edx, 16
+       cmp     ecx, 16
+       je      .c1b2
+       jmp     .c1b3
+
+.c1_next2:                             ;       } else {
+       ;; ecx          cbits
+       ;; edx          current brword 'b'
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       add     edi, 32
+       sub     edi, ecx                ;         uval += FLAC__BITS_PER_WORD - cbits;
+                                       ;         crc16_update_word_(br, br->buffer[cwords]);
+       push    edi                     ;               [need more registers]
+       bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+       mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
+       mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+       mov     edi, _FLAC__crc16_table
+%else
+       mov     edi, FLAC__crc16_table
+%endif
+       ;; eax (ax)     crc a.k.a. br->read_crc
+       ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
+       ;; ecx          br->crc16_align
+       ;; edx          byteswapped brword to CRC
+       ;; esi          cwords
+       ;; edi          unsigned FLAC__crc16_table[]
+       ;; ebp          br
+       test    ecx, ecx                ;               switch(br->crc16_align) ...
+       jnz     .c1b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c1b0: xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c1b1: xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shr     edx, 16
+.c1b2: xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c1b3: xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       movzx   eax, ax
+       mov     [ebp + 24], eax         ;               br->read_crc <- crc
+       pop     edi
+
+       add     esi, byte 1             ;         cwords++;
+       xor     ecx, ecx                ;         cbits = 0;
+                                       ;         /* didn't find stop bit yet, have to keep going... */
+                                       ;       }
+
+       cmp     esi, [ebp + 8]          ;     } while(cwords < br->words)   /* if we've not consumed up to a partial tail word... */
+       jb      near .c1_loop
+
+.c1_next1:
+       ; at this point we've eaten up all the whole words; have to try
+       ; reading through any tail bytes before calling the read callback.
+       ; this is a repeat of the above logic adjusted for the fact we
+       ; don't have a whole word.  note though if the client is feeding
+       ; us data a byte at a time (unlikely), br->consumed_bits may not
+       ; be zero.
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       mov     edx, [ebp + 12]         ;     edx <- br->bytes
+       test    edx, edx
+       jz      .read1                  ;     if(br->bytes) {  [NOTE: this case is rare so it doesn't have to be all that fast ]
+       mov     ebx, [ebp]
+       shl     edx, 3                  ;       edx <- const unsigned end = br->bytes * 8;
+       mov     eax, [ebx + 4*esi]      ;       b = br->buffer[cwords]
+       xchg    edx, ecx                ;       [edx <- cbits , ecx <- end]
+       mov     ebx, 0xffffffff         ;       ebx <- FLAC__WORD_ALL_ONES
+       shr     ebx, cl                 ;       ebx <- FLAC__WORD_ALL_ONES >> end
+       not     ebx                     ;       ebx <- ~(FLAC__WORD_ALL_ONES >> end)
+       xchg    edx, ecx                ;       [edx <- end , ecx <- cbits]
+       and     eax, ebx                ;       b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end));
+       shl     eax, cl                 ;       b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
+       test    eax, eax                ;         (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+       jz      .c1_next3               ;       if(b) {
+       bsr     ebx, eax
+       not     ebx
+       and     ebx, 31                 ;         ebx = 'i' = # of leading 0 bits in 'b' (eax)
+       add     ecx, ebx                ;         cbits += i;
+       add     edi, ebx                ;         uval += i;
+       add     ecx, byte 1             ;         cbits++; /* skip over stop bit */
+       jmp     short .break1           ;         goto break1;
+.c1_next3:                             ;       } else {
+       sub     edi, ecx
+       add     edi, edx                ;         uval += end - cbits;
+       add     ecx, edx                ;         cbits += end
+                                       ;         /* didn't find stop bit yet, have to keep going... */
+                                       ;       }
+                                       ;     }
+.read1:
+       ; flush registers and read; bitreader_read_from_client_() does
+       ; not touch br->consumed_bits at all but we still need to set
+       ; it in case it fails and we have to return false.
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       mov     [ebp + 16], esi         ;     br->consumed_words = cwords;
+       mov     [ebp + 20], ecx         ;     br->consumed_bits = cbits;
+       push    ecx                     ;     /* save */
+       push    ebp                     ;     /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+       call    _bitreader_read_from_client_
+%else
+       call    bitreader_read_from_client_
+%endif
+       pop     edx                     ;     /* discard, unused */
+       pop     ecx                     ;     /* restore */
+       mov     esi, [ebp + 16]         ;     cwords = br->consumed_words;
+                                       ;     ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+       mov     ebx, [ebp + 8]          ;       ebx <- br->words
+       sub     ebx, esi                ;       ebx <- br->words-cwords
+       shl     ebx, 2                  ;       ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+       add     ebx, [ebp + 12]         ;       ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+       shl     ebx, 3                  ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+       sub     ebx, ecx                ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+       add     ebx, edi                ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval
+                                       ;           + uval to offset our count by the # of unary bits already
+                                       ;           consumed before the read, because we will add these back
+                                       ;           in all at once at break1
+       mov     [esp], ebx              ;       ucbits <- ebx
+       test    eax, eax                ;     if(!bitreader_read_from_client_(br))
+       jnz     near .unary_loop
+       jmp     .end                    ;       return false; /* eax (the return value) is already 0 */
+                                       ;   } /* end while(1) unary part */
+
+       ALIGN 16
+.break1:
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       ;; [esp]        ucbits
+       sub     [esp], edi              ;   ucbits -= uval;
+       sub     dword [esp], byte 1     ;   ucbits--; /* account for stop bit */
+
+       ;
+       ; read binary part
+       ;
+       mov     ebx, [esp + 36]         ;   ebx <- parameter
+       test    ebx, ebx                ;   if(parameter) {
+       jz      near .break2
+.read2:
+       cmp     [esp], ebx              ;     while(ucbits < parameter) {
+       jae     .c2_next1
+       ; flush registers and read; bitreader_read_from_client_() does
+       ; not touch br->consumed_bits at all but we still need to set
+       ; it in case it fails and we have to return false.
+       mov     [ebp + 16], esi         ;       br->consumed_words = cwords;
+       mov     [ebp + 20], ecx         ;       br->consumed_bits = cbits;
+       push    ecx                     ;       /* save */
+       push    ebp                     ;       /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+       call    _bitreader_read_from_client_
+%else
+       call    bitreader_read_from_client_
+%endif
+       pop     edx                     ;       /* discard, unused */
+       pop     ecx                     ;       /* restore */
+       mov     esi, [ebp + 16]         ;       cwords = br->consumed_words;
+                                       ;       ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+       mov     edx, [ebp + 8]          ;         edx <- br->words
+       sub     edx, esi                ;         edx <- br->words-cwords
+       shl     edx, 2                  ;         edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+       add     edx, [ebp + 12]         ;         edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+       shl     edx, 3                  ;         edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+       sub     edx, ecx                ;         edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+       mov     [esp], edx              ;         ucbits <- edx
+       test    eax, eax                ;       if(!bitreader_read_from_client_(br))
+       jnz     .read2
+       jmp     .end                    ;         return false; /* eax (the return value) is already 0 */
+                                       ;     }
+.c2_next1:
+       ;; ebx          parameter
+       ;; ecx          cbits
+       ;; esi          cwords
+       ;; edi          uval
+       ;; ebp          br
+       ;; [esp]        ucbits
+       cmp     esi, [ebp + 8]          ;     if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+       jae     near .c2_next2
+       test    ecx, ecx                ;       if(cbits) {
+       jz      near .c2_next3          ;         /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+       mov     eax, 32
+       mov     edx, [ebp]
+       sub     eax, ecx                ;         const unsigned n = FLAC__BITS_PER_WORD - cbits;
+       mov     edx, [edx + 4*esi]      ;         const brword word = br->buffer[cwords];
+       cmp     ebx, eax                ;         if(parameter < n) {
+       jae     .c2_next4
+                                       ;           uval <<= parameter;
+                                       ;           uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
+       shl     edx, cl
+       xchg    ebx, ecx
+       shld    edi, edx, cl
+       add     ebx, ecx                ;           cbits += parameter;
+       xchg    ebx, ecx                ;           ebx <- parameter, ecx <- cbits
+       jmp     .break2                 ;           goto break2;
+                                       ;         }
+.c2_next4:
+                                       ;         uval <<= n;
+                                       ;         uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+%if 1
+       rol     edx, cl                 ;            @@@@@@OPT: may be faster to use rol to save edx so we can restore it for CRC'ing
+                                       ;            @@@@@@OPT: or put parameter in ch instead and free up ebx completely again
+%else
+       shl     edx, cl
+%endif
+       xchg    eax, ecx
+       shld    edi, edx, cl
+       xchg    eax, ecx
+%if 1
+       ror     edx, cl                 ;            restored.
+%else
+       mov     edx, [ebp]
+       mov     edx, [edx + 4*esi]
+%endif
+                                       ;         crc16_update_word_(br, br->buffer[cwords]);
+       push    edi                     ;               [need more registers]
+       push    ebx                     ;               [need more registers]
+       push    eax                     ;               [need more registers]
+       bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+       mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
+       mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+       mov     edi, _FLAC__crc16_table
+%else
+       mov     edi, FLAC__crc16_table
+%endif
+       ;; eax (ax)     crc a.k.a. br->read_crc
+       ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
+       ;; ecx          br->crc16_align
+       ;; edx          byteswapped brword to CRC
+       ;; esi          cwords
+       ;; edi          unsigned FLAC__crc16_table[]
+       ;; ebp          br
+       test    ecx, ecx                ;               switch(br->crc16_align) ...
+       jnz     .c2b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c2b0: xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c2b1: xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+       shr     edx, 16
+.c2b2: xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
+       movzx   ebx, dl
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c2b3: xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
+       movzx   ebx, dh
+       mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       shl     eax, 8                  ;               ax <- (crc<<8)
+       xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+       movzx   eax, ax
+       mov     [ebp + 24], eax         ;               br->read_crc <- crc
+       pop     eax
+       pop     ebx
+       pop     edi
+       add     esi, byte 1             ;         cwords++;
+       mov     ecx, ebx
+       sub     ecx, eax                ;         cbits = parameter - n;
+       jz      .break2                 ;         if(cbits) { /* parameter > n, i.e. if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+                                       ;           uval <<= cbits;
+                                       ;           uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+       mov     eax, [ebp]
+       mov     eax, [eax + 4*esi]
+       shld    edi, eax, cl
+                                       ;         }
+       jmp     .break2                 ;         goto break2;
+
+       ;; this section relocated out of the way for performance
+.c2b4:
+       mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
+       cmp     ecx, 8
+       je      .c2b1
+       shr     edx, 16
+       cmp     ecx, 16
+       je      .c2b2
+       jmp     .c2b3
+
+.c2_next3:                             ;       } else {
+       mov     ecx, ebx                ;         cbits = parameter;
+                                       ;         uval <<= cbits;
+                                       ;         uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+       mov     eax, [ebp]
+       mov     eax, [eax + 4*esi]
+       shld    edi, eax, cl
+       jmp     .break2                 ;         goto break2;
+                                       ;       }
+.c2_next2:                             ;     } else {
+       ; in this case we're starting our read at a partial tail word;
+       ; the reader has guaranteed that we have at least 'parameter'
+       ; bits available to read, which makes this case simpler.
+                                       ;       uval <<= parameter;
+                                       ;       if(cbits) {
+                                       ;         /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+                                       ;         uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
+                                       ;         cbits += parameter;
+                                       ;         goto break2;
+                                       ;       } else {
+                                       ;         cbits = parameter;
+                                       ;         uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+                                       ;         goto break2;
+                                       ;       }
+                                       ;       the above is much shorter in assembly:
+       mov     eax, [ebp]
+       mov     eax, [eax + 4*esi]      ;       eax <- br->buffer[cwords]
+       shl     eax, cl                 ;       eax <- br->buffer[cwords] << cbits
+       add     ecx, ebx                ;       cbits += parameter
+       xchg    ebx, ecx                ;       ebx <- cbits, ecx <- parameter
+       shld    edi, eax, cl            ;       uval <<= parameter <<< 'parameter' bits of tail word
+       xchg    ebx, ecx                ;       ebx <- parameter, ecx <- cbits
+                                       ;     }
+                                       ;   }
+.break2:
+       sub     [esp], ebx              ;   ucbits -= parameter;
+
+       ;
+       ; compose the value
+       ;
+       mov     ebx, [esp + 28]         ;   ebx <- vals
+       mov     edx, edi                ;   edx <- uval
+       and     edi, 1                  ;   edi <- uval & 1
+       shr     edx, 1                  ;   edx <- uval >> 1
+       neg     edi                     ;   edi <- -(int)(uval & 1)
+       xor     edx, edi                ;   edx <- (uval >> 1 ^ -(int)(uval & 1))
+       mov     [ebx], edx              ;   *vals <- edx
+       sub     dword [esp + 32], byte 1        ;   --nvals;
+       jz      .finished               ;   if(nvals == 0) /* jump to finish */
+       xor     edi, edi                ;   uval = 0;
+       add     dword [esp + 28], 4     ;   ++vals
+       jmp     .val_loop               ; }
+
+.finished:
+       mov     [ebp + 16], esi         ; br->consumed_words = cwords;
+       mov     [ebp + 20], ecx         ; br->consumed_bits = cbits;
+       mov     eax, 1
+.end:
+       add     esp, 4
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+       section .note.GNU-stack noalloc
+%endif
diff --git a/src/libFLAC/ia32/cpu_asm.nasm b/src/libFLAC/ia32/cpu_asm.nasm
new file mode 100644 (file)
index 0000000..f5eb110
--- /dev/null
@@ -0,0 +1,121 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+       data_section
+
+cglobal FLAC__cpu_have_cpuid_asm_ia32
+cglobal FLAC__cpu_info_asm_ia32
+cglobal FLAC__cpu_info_extended_amd_asm_ia32
+
+       code_section
+
+; **********************************************************************
+;
+; FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32()
+;
+
+cident FLAC__cpu_have_cpuid_asm_ia32
+       push    ebx
+       pushfd
+       pop     eax
+       mov     edx, eax
+       xor     eax, 0x00200000
+       push    eax
+       popfd
+       pushfd
+       pop     eax
+       cmp     eax, edx
+       jz      .no_cpuid
+       mov     eax, 1
+       jmp     .end
+.no_cpuid:
+       xor     eax, eax
+.end:
+       pop     ebx
+       ret
+
+; **********************************************************************
+;
+; void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx)
+;
+
+cident FLAC__cpu_info_asm_ia32
+       ;[esp + 8] == flags_edx
+       ;[esp + 12] == flags_ecx
+
+       push    ebx
+       call    FLAC__cpu_have_cpuid_asm_ia32
+       test    eax, eax
+       jz      .no_cpuid
+       mov     eax, 1
+       cpuid
+       mov     ebx, [esp + 8]
+       mov     [ebx], edx
+       mov     ebx, [esp + 12]
+       mov     [ebx], ecx
+       jmp     .end
+.no_cpuid
+       xor     eax, eax
+       mov     ebx, [esp + 8]
+       mov     [ebx], eax
+       mov     ebx, [esp + 12]
+       mov     [ebx], eax
+.end
+       pop     ebx
+       ret
+
+cident FLAC__cpu_info_extended_amd_asm_ia32
+       push    ebx
+       call    FLAC__cpu_have_cpuid_asm_ia32
+       test    eax, eax
+       jz      .no_cpuid
+       mov     eax, 0x80000000
+       cpuid
+       cmp     eax, 0x80000001
+       jb      .no_cpuid
+       mov     eax, 0x80000001
+       cpuid
+       mov     eax, edx
+       jmp     .end
+.no_cpuid
+       xor     eax, eax
+.end
+       pop     ebx
+       ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+       section .note.GNU-stack noalloc
+%endif
diff --git a/src/libFLAC/ia32/fixed_asm.nasm b/src/libFLAC/ia32/fixed_asm.nasm
new file mode 100644 (file)
index 0000000..0185f4d
--- /dev/null
@@ -0,0 +1,312 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+       data_section
+
+cglobal FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+       code_section
+
+; **********************************************************************
+;
+; unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 *data, unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+; {
+;      FLAC__int32 last_error_0 = data[-1];
+;      FLAC__int32 last_error_1 = data[-1] - data[-2];
+;      FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+;      FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+;      FLAC__int32 error, save;
+;      FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+;      unsigned i, order;
+;
+;      for(i = 0; i < data_len; i++) {
+;              error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+;              error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+;              error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+;              error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+;              error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+;      }
+;
+;      if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+;              order = 0;
+;      else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+;              order = 1;
+;      else if(total_error_2 < min(total_error_3, total_error_4))
+;              order = 2;
+;      else if(total_error_3 < total_error_4)
+;              order = 3;
+;      else
+;              order = 4;
+;
+;      residual_bits_per_sample[0] = (FLAC__float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;      residual_bits_per_sample[1] = (FLAC__float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;      residual_bits_per_sample[2] = (FLAC__float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;      residual_bits_per_sample[3] = (FLAC__float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;      residual_bits_per_sample[4] = (FLAC__float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;
+;      return order;
+; }
+       ALIGN 16
+cident FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+       ; esp + 36 == data[]
+       ; esp + 40 == data_len
+       ; esp + 44 == residual_bits_per_sample[]
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+       sub     esp, byte 16
+       ; qword [esp] == temp space for loading FLAC__uint64s to FPU regs
+
+       ; ebx == &data[i]
+       ; ecx == loop counter (i)
+       ; ebp == order
+       ; mm0 == total_error_1:total_error_0
+       ; mm1 == total_error_2:total_error_3
+       ; mm2 == :total_error_4
+       ; mm3 == last_error_1:last_error_0
+       ; mm4 == last_error_2:last_error_3
+
+       mov     ecx, [esp + 40]                 ; ecx = data_len
+       test    ecx, ecx
+       jz      near .data_len_is_0
+
+       mov     ebx, [esp + 36]                 ; ebx = data[]
+       movd    mm3, [ebx - 4]                  ; mm3 = 0:last_error_0
+       movd    mm2, [ebx - 8]                  ; mm2 = 0:data[-2]
+       movd    mm1, [ebx - 12]                 ; mm1 = 0:data[-3]
+       movd    mm0, [ebx - 16]                 ; mm0 = 0:data[-4]
+       movq    mm5, mm3                        ; mm5 = 0:last_error_0
+       psubd   mm5, mm2                        ; mm5 = 0:last_error_1
+       punpckldq       mm3, mm5                ; mm3 = last_error_1:last_error_0
+       psubd   mm2, mm1                        ; mm2 = 0:data[-2] - data[-3]
+       psubd   mm5, mm2                        ; mm5 = 0:last_error_2
+       movq    mm4, mm5                        ; mm4 = 0:last_error_2
+       psubd   mm4, mm2                        ; mm4 = 0:last_error_2 - (data[-2] - data[-3])
+       paddd   mm4, mm1                        ; mm4 = 0:last_error_2 - (data[-2] - 2 * data[-3])
+       psubd   mm4, mm0                        ; mm4 = 0:last_error_3
+       punpckldq       mm4, mm5                ; mm4 = last_error_2:last_error_3
+       pxor    mm0, mm0                        ; mm0 = total_error_1:total_error_0
+       pxor    mm1, mm1                        ; mm1 = total_error_2:total_error_3
+       pxor    mm2, mm2                        ; mm2 = 0:total_error_4
+
+       ALIGN 16
+.loop:
+       movd    mm7, [ebx]                      ; mm7 = 0:error_0
+       add     ebx, byte 4
+       movq    mm6, mm7                        ; mm6 = 0:error_0
+       psubd   mm7, mm3                        ; mm7 = :error_1
+       punpckldq       mm6, mm7                ; mm6 = error_1:error_0
+       movq    mm5, mm6                        ; mm5 = error_1:error_0
+       movq    mm7, mm6                        ; mm7 = error_1:error_0
+       psubd   mm5, mm3                        ; mm5 = error_2:
+       movq    mm3, mm6                        ; mm3 = error_1:error_0 
+       psrad   mm6, 31
+       pxor    mm7, mm6
+       psubd   mm7, mm6                        ; mm7 = abs(error_1):abs(error_0)
+       paddd   mm0, mm7                        ; mm0 = total_error_1:total_error_0
+       movq    mm6, mm5                        ; mm6 = error_2:
+       psubd   mm5, mm4                        ; mm5 = error_3:
+       punpckhdq       mm5, mm6                ; mm5 = error_2:error_3
+       movq    mm7, mm5                        ; mm7 = error_2:error_3
+       movq    mm6, mm5                        ; mm6 = error_2:error_3
+       psubd   mm5, mm4                        ; mm5 = :error_4
+       movq    mm4, mm6                        ; mm4 = error_2:error_3
+       psrad   mm6, 31
+       pxor    mm7, mm6
+       psubd   mm7, mm6                        ; mm7 = abs(error_2):abs(error_3)
+       paddd   mm1, mm7                        ; mm1 = total_error_2:total_error_3
+       movq    mm6, mm5                        ; mm6 = :error_4
+       psrad   mm5, 31
+       pxor    mm6, mm5
+       psubd   mm6, mm5                        ; mm6 = :abs(error_4)
+       paddd   mm2, mm6                        ; mm2 = :total_error_4
+       
+       dec     ecx
+       jnz     short .loop
+
+;      if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+;              order = 0;
+;      else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+;              order = 1;
+;      else if(total_error_2 < min(total_error_3, total_error_4))
+;              order = 2;
+;      else if(total_error_3 < total_error_4)
+;              order = 3;
+;      else
+;              order = 4;
+       movq    mm3, mm0                        ; mm3 = total_error_1:total_error_0
+       movd    edi, mm2                        ; edi = total_error_4
+       movd    esi, mm1                        ; esi = total_error_3
+       movd    eax, mm0                        ; eax = total_error_0
+       punpckhdq       mm1, mm1                ; mm1 = total_error_2:total_error_2
+       punpckhdq       mm3, mm3                ; mm3 = total_error_1:total_error_1
+       movd    edx, mm1                        ; edx = total_error_2
+       movd    ecx, mm3                        ; ecx = total_error_1
+
+       xor     ebx, ebx
+       xor     ebp, ebp
+       inc     ebx
+       cmp     ecx, eax
+       cmovb   eax, ecx                        ; eax = min(total_error_0, total_error_1)
+       cmovbe  ebp, ebx
+       inc     ebx
+       cmp     edx, eax
+       cmovb   eax, edx                        ; eax = min(total_error_0, total_error_1, total_error_2)
+       cmovbe  ebp, ebx
+       inc     ebx
+       cmp     esi, eax
+       cmovb   eax, esi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3)
+       cmovbe  ebp, ebx
+       inc     ebx
+       cmp     edi, eax
+       cmovb   eax, edi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3, total_error_4)
+       cmovbe  ebp, ebx
+       movd    ebx, mm0                        ; ebx = total_error_0
+       emms
+
+       ;       residual_bits_per_sample[0] = (FLAC__float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       ;       residual_bits_per_sample[1] = (FLAC__float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       ;       residual_bits_per_sample[2] = (FLAC__float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       ;       residual_bits_per_sample[3] = (FLAC__float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       ;       residual_bits_per_sample[4] = (FLAC__float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+       xor     eax, eax
+       fild    dword [esp + 40]                ; ST = data_len (NOTE: assumes data_len is <2gigs)
+.rbps_0:
+       test    ebx, ebx
+       jz      .total_error_0_is_0
+       fld1                                    ; ST = 1.0 data_len
+       mov     [esp], ebx
+       mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_0
+       mov     ebx, [esp + 44]
+       fild    qword [esp]                     ; ST = total_error_0 1.0 data_len
+       fdiv    st2                             ; ST = total_error_0/data_len 1.0 data_len
+       fldln2                                  ; ST = ln2 total_error_0/data_len 1.0 data_len
+       fmulp   st1                             ; ST = ln2*total_error_0/data_len 1.0 data_len
+       fyl2x                                   ; ST = log2(ln2*total_error_0/data_len) data_len
+       fstp    dword [ebx]                     ; residual_bits_per_sample[0] = log2(ln2*total_error_0/data_len)   ST = data_len
+       jmp     short .rbps_1
+.total_error_0_is_0:
+       mov     ebx, [esp + 44]
+       mov     [ebx], eax                      ; residual_bits_per_sample[0] = 0.0
+.rbps_1:
+       test    ecx, ecx
+       jz      .total_error_1_is_0
+       fld1                                    ; ST = 1.0 data_len
+       mov     [esp], ecx
+       mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_1
+       fild    qword [esp]                     ; ST = total_error_1 1.0 data_len
+       fdiv    st2                             ; ST = total_error_1/data_len 1.0 data_len
+       fldln2                                  ; ST = ln2 total_error_1/data_len 1.0 data_len
+       fmulp   st1                             ; ST = ln2*total_error_1/data_len 1.0 data_len
+       fyl2x                                   ; ST = log2(ln2*total_error_1/data_len) data_len
+       fstp    dword [ebx + 4]                 ; residual_bits_per_sample[1] = log2(ln2*total_error_1/data_len)   ST = data_len
+       jmp     short .rbps_2
+.total_error_1_is_0:
+       mov     [ebx + 4], eax                  ; residual_bits_per_sample[1] = 0.0
+.rbps_2:
+       test    edx, edx
+       jz      .total_error_2_is_0
+       fld1                                    ; ST = 1.0 data_len
+       mov     [esp], edx
+       mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_2
+       fild    qword [esp]                     ; ST = total_error_2 1.0 data_len
+       fdiv    st2                             ; ST = total_error_2/data_len 1.0 data_len
+       fldln2                                  ; ST = ln2 total_error_2/data_len 1.0 data_len
+       fmulp   st1                             ; ST = ln2*total_error_2/data_len 1.0 data_len
+       fyl2x                                   ; ST = log2(ln2*total_error_2/data_len) data_len
+       fstp    dword [ebx + 8]                 ; residual_bits_per_sample[2] = log2(ln2*total_error_2/data_len)   ST = data_len
+       jmp     short .rbps_3
+.total_error_2_is_0:
+       mov     [ebx + 8], eax                  ; residual_bits_per_sample[2] = 0.0
+.rbps_3:
+       test    esi, esi
+       jz      .total_error_3_is_0
+       fld1                                    ; ST = 1.0 data_len
+       mov     [esp], esi
+       mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_3
+       fild    qword [esp]                     ; ST = total_error_3 1.0 data_len
+       fdiv    st2                             ; ST = total_error_3/data_len 1.0 data_len
+       fldln2                                  ; ST = ln2 total_error_3/data_len 1.0 data_len
+       fmulp   st1                             ; ST = ln2*total_error_3/data_len 1.0 data_len
+       fyl2x                                   ; ST = log2(ln2*total_error_3/data_len) data_len
+       fstp    dword [ebx + 12]                ; residual_bits_per_sample[3] = log2(ln2*total_error_3/data_len)   ST = data_len
+       jmp     short .rbps_4
+.total_error_3_is_0:
+       mov     [ebx + 12], eax                 ; residual_bits_per_sample[3] = 0.0
+.rbps_4:
+       test    edi, edi
+       jz      .total_error_4_is_0
+       fld1                                    ; ST = 1.0 data_len
+       mov     [esp], edi
+       mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_4
+       fild    qword [esp]                     ; ST = total_error_4 1.0 data_len
+       fdiv    st2                             ; ST = total_error_4/data_len 1.0 data_len
+       fldln2                                  ; ST = ln2 total_error_4/data_len 1.0 data_len
+       fmulp   st1                             ; ST = ln2*total_error_4/data_len 1.0 data_len
+       fyl2x                                   ; ST = log2(ln2*total_error_4/data_len) data_len
+       fstp    dword [ebx + 16]                ; residual_bits_per_sample[4] = log2(ln2*total_error_4/data_len)   ST = data_len
+       jmp     short .rbps_end
+.total_error_4_is_0:
+       mov     [ebx + 16], eax                 ; residual_bits_per_sample[4] = 0.0
+.rbps_end:
+       fstp    st0                             ; ST = [empty]
+       jmp     short .end
+.data_len_is_0:
+       ; data_len == 0, so residual_bits_per_sample[*] = 0.0
+       xor     ebp, ebp
+       mov     edi, [esp + 44]
+       mov     [edi], ebp
+       mov     [edi + 4], ebp
+       mov     [edi + 8], ebp
+       mov     [edi + 12], ebp
+       mov     [edi + 16], ebp
+       add     ebp, byte 4                     ; order = 4
+
+.end:
+       mov     eax, ebp                        ; return order
+       add     esp, byte 16
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+       section .note.GNU-stack noalloc
+%endif
diff --git a/src/libFLAC/ia32/lpc_asm.nasm b/src/libFLAC/ia32/lpc_asm.nasm
new file mode 100644 (file)
index 0000000..4bc4c91
--- /dev/null
@@ -0,0 +1,1511 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+       data_section
+
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+cglobal FLAC__lpc_restore_signal_asm_ia32
+cglobal FLAC__lpc_restore_signal_asm_ia32_mmx
+
+       code_section
+
+; **********************************************************************
+;
+; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+; {
+;      FLAC__real d;
+;      unsigned sample, coeff;
+;      const unsigned limit = data_len - lag;
+;
+;      FLAC__ASSERT(lag > 0);
+;      FLAC__ASSERT(lag <= data_len);
+;
+;      for(coeff = 0; coeff < lag; coeff++)
+;              autoc[coeff] = 0.0;
+;      for(sample = 0; sample <= limit; sample++) {
+;              d = data[sample];
+;              for(coeff = 0; coeff < lag; coeff++)
+;                      autoc[coeff] += d * data[sample+coeff];
+;      }
+;      for(; sample < data_len; sample++) {
+;              d = data[sample];
+;              for(coeff = 0; coeff < data_len - sample; coeff++)
+;                      autoc[coeff] += d * data[sample+coeff];
+;      }
+; }
+;
+       ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32
+       ;[esp + 28] == autoc[]
+       ;[esp + 24] == lag
+       ;[esp + 20] == data_len
+       ;[esp + 16] == data[]
+
+       ;ASSERT(lag > 0)
+       ;ASSERT(lag <= 33)
+       ;ASSERT(lag <= data_len)
+
+.begin:
+       push    esi
+       push    edi
+       push    ebx
+
+       ;       for(coeff = 0; coeff < lag; coeff++)
+       ;               autoc[coeff] = 0.0;
+       mov     edi, [esp + 28]                 ; edi == autoc
+       mov     ecx, [esp + 24]                 ; ecx = # of dwords (=lag) of 0 to write
+       xor     eax, eax
+       rep     stosd
+
+       ;       const unsigned limit = data_len - lag;
+       mov     eax, [esp + 24]                 ; eax == lag
+       mov     ecx, [esp + 20]
+       sub     ecx, eax                        ; ecx == limit
+
+       mov     edi, [esp + 28]                 ; edi == autoc
+       mov     esi, [esp + 16]                 ; esi == data
+       inc     ecx                             ; we are looping <= limit so we add one to the counter
+
+       ;       for(sample = 0; sample <= limit; sample++) {
+       ;               d = data[sample];
+       ;               for(coeff = 0; coeff < lag; coeff++)
+       ;                       autoc[coeff] += d * data[sample+coeff];
+       ;       }
+       fld     dword [esi]                     ; ST = d <- data[sample]
+       ; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+       lea     edx, [eax + eax*2]
+       neg     edx
+       lea     edx, [eax + edx*4 + .jumper1_0 - .get_eip1]
+       call    .get_eip1
+.get_eip1:
+       pop     ebx
+       add     edx, ebx
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       cmp     eax, 33
+       jne     .loop1_start
+       sub     edx, byte 9                     ; compensate for the longer opcodes on the first iteration
+.loop1_start:
+       jmp     edx
+
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (32*4)]            ; ST = d*data[sample+32] d              WATCHOUT: not a byte displacement here!
+       fadd    dword [edi + (32*4)]            ; ST = autoc[32]+d*data[sample+32] d    WATCHOUT: not a byte displacement here!
+       fstp    dword [edi + (32*4)]            ; autoc[32]+=d*data[sample+32]  ST = d  WATCHOUT: not a byte displacement here!
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (31*4)]            ; ST = d*data[sample+31] d
+       fadd    dword [edi + (31*4)]            ; ST = autoc[31]+d*data[sample+31] d
+       fstp    dword [edi + (31*4)]            ; autoc[31]+=d*data[sample+31]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (30*4)]            ; ST = d*data[sample+30] d
+       fadd    dword [edi + (30*4)]            ; ST = autoc[30]+d*data[sample+30] d
+       fstp    dword [edi + (30*4)]            ; autoc[30]+=d*data[sample+30]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (29*4)]            ; ST = d*data[sample+29] d
+       fadd    dword [edi + (29*4)]            ; ST = autoc[29]+d*data[sample+29] d
+       fstp    dword [edi + (29*4)]            ; autoc[29]+=d*data[sample+29]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (28*4)]            ; ST = d*data[sample+28] d
+       fadd    dword [edi + (28*4)]            ; ST = autoc[28]+d*data[sample+28] d
+       fstp    dword [edi + (28*4)]            ; autoc[28]+=d*data[sample+28]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (27*4)]            ; ST = d*data[sample+27] d
+       fadd    dword [edi + (27*4)]            ; ST = autoc[27]+d*data[sample+27] d
+       fstp    dword [edi + (27*4)]            ; autoc[27]+=d*data[sample+27]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (26*4)]            ; ST = d*data[sample+26] d
+       fadd    dword [edi + (26*4)]            ; ST = autoc[26]+d*data[sample+26] d
+       fstp    dword [edi + (26*4)]            ; autoc[26]+=d*data[sample+26]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (25*4)]            ; ST = d*data[sample+25] d
+       fadd    dword [edi + (25*4)]            ; ST = autoc[25]+d*data[sample+25] d
+       fstp    dword [edi + (25*4)]            ; autoc[25]+=d*data[sample+25]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (24*4)]            ; ST = d*data[sample+24] d
+       fadd    dword [edi + (24*4)]            ; ST = autoc[24]+d*data[sample+24] d
+       fstp    dword [edi + (24*4)]            ; autoc[24]+=d*data[sample+24]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (23*4)]            ; ST = d*data[sample+23] d
+       fadd    dword [edi + (23*4)]            ; ST = autoc[23]+d*data[sample+23] d
+       fstp    dword [edi + (23*4)]            ; autoc[23]+=d*data[sample+23]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (22*4)]            ; ST = d*data[sample+22] d
+       fadd    dword [edi + (22*4)]            ; ST = autoc[22]+d*data[sample+22] d
+       fstp    dword [edi + (22*4)]            ; autoc[22]+=d*data[sample+22]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (21*4)]            ; ST = d*data[sample+21] d
+       fadd    dword [edi + (21*4)]            ; ST = autoc[21]+d*data[sample+21] d
+       fstp    dword [edi + (21*4)]            ; autoc[21]+=d*data[sample+21]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (20*4)]            ; ST = d*data[sample+20] d
+       fadd    dword [edi + (20*4)]            ; ST = autoc[20]+d*data[sample+20] d
+       fstp    dword [edi + (20*4)]            ; autoc[20]+=d*data[sample+20]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (19*4)]            ; ST = d*data[sample+19] d
+       fadd    dword [edi + (19*4)]            ; ST = autoc[19]+d*data[sample+19] d
+       fstp    dword [edi + (19*4)]            ; autoc[19]+=d*data[sample+19]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (18*4)]            ; ST = d*data[sample+18] d
+       fadd    dword [edi + (18*4)]            ; ST = autoc[18]+d*data[sample+18] d
+       fstp    dword [edi + (18*4)]            ; autoc[18]+=d*data[sample+18]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (17*4)]            ; ST = d*data[sample+17] d
+       fadd    dword [edi + (17*4)]            ; ST = autoc[17]+d*data[sample+17] d
+       fstp    dword [edi + (17*4)]            ; autoc[17]+=d*data[sample+17]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (16*4)]            ; ST = d*data[sample+16] d
+       fadd    dword [edi + (16*4)]            ; ST = autoc[16]+d*data[sample+16] d
+       fstp    dword [edi + (16*4)]            ; autoc[16]+=d*data[sample+16]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (15*4)]            ; ST = d*data[sample+15] d
+       fadd    dword [edi + (15*4)]            ; ST = autoc[15]+d*data[sample+15] d
+       fstp    dword [edi + (15*4)]            ; autoc[15]+=d*data[sample+15]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (14*4)]            ; ST = d*data[sample+14] d
+       fadd    dword [edi + (14*4)]            ; ST = autoc[14]+d*data[sample+14] d
+       fstp    dword [edi + (14*4)]            ; autoc[14]+=d*data[sample+14]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (13*4)]            ; ST = d*data[sample+13] d
+       fadd    dword [edi + (13*4)]            ; ST = autoc[13]+d*data[sample+13] d
+       fstp    dword [edi + (13*4)]            ; autoc[13]+=d*data[sample+13]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (12*4)]            ; ST = d*data[sample+12] d
+       fadd    dword [edi + (12*4)]            ; ST = autoc[12]+d*data[sample+12] d
+       fstp    dword [edi + (12*4)]            ; autoc[12]+=d*data[sample+12]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (11*4)]            ; ST = d*data[sample+11] d
+       fadd    dword [edi + (11*4)]            ; ST = autoc[11]+d*data[sample+11] d
+       fstp    dword [edi + (11*4)]            ; autoc[11]+=d*data[sample+11]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (10*4)]            ; ST = d*data[sample+10] d
+       fadd    dword [edi + (10*4)]            ; ST = autoc[10]+d*data[sample+10] d
+       fstp    dword [edi + (10*4)]            ; autoc[10]+=d*data[sample+10]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 9*4)]            ; ST = d*data[sample+9] d
+       fadd    dword [edi + ( 9*4)]            ; ST = autoc[9]+d*data[sample+9] d
+       fstp    dword [edi + ( 9*4)]            ; autoc[9]+=d*data[sample+9]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 8*4)]            ; ST = d*data[sample+8] d
+       fadd    dword [edi + ( 8*4)]            ; ST = autoc[8]+d*data[sample+8] d
+       fstp    dword [edi + ( 8*4)]            ; autoc[8]+=d*data[sample+8]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 7*4)]            ; ST = d*data[sample+7] d
+       fadd    dword [edi + ( 7*4)]            ; ST = autoc[7]+d*data[sample+7] d
+       fstp    dword [edi + ( 7*4)]            ; autoc[7]+=d*data[sample+7]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 6*4)]            ; ST = d*data[sample+6] d
+       fadd    dword [edi + ( 6*4)]            ; ST = autoc[6]+d*data[sample+6] d
+       fstp    dword [edi + ( 6*4)]            ; autoc[6]+=d*data[sample+6]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 5*4)]            ; ST = d*data[sample+4] d
+       fadd    dword [edi + ( 5*4)]            ; ST = autoc[4]+d*data[sample+4] d
+       fstp    dword [edi + ( 5*4)]            ; autoc[4]+=d*data[sample+4]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 4*4)]            ; ST = d*data[sample+4] d
+       fadd    dword [edi + ( 4*4)]            ; ST = autoc[4]+d*data[sample+4] d
+       fstp    dword [edi + ( 4*4)]            ; autoc[4]+=d*data[sample+4]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 3*4)]            ; ST = d*data[sample+3] d
+       fadd    dword [edi + ( 3*4)]            ; ST = autoc[3]+d*data[sample+3] d
+       fstp    dword [edi + ( 3*4)]            ; autoc[3]+=d*data[sample+3]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 2*4)]            ; ST = d*data[sample+2] d
+       fadd    dword [edi + ( 2*4)]            ; ST = autoc[2]+d*data[sample+2] d
+       fstp    dword [edi + ( 2*4)]            ; autoc[2]+=d*data[sample+2]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 1*4)]            ; ST = d*data[sample+1] d
+       fadd    dword [edi + ( 1*4)]            ; ST = autoc[1]+d*data[sample+1] d
+       fstp    dword [edi + ( 1*4)]            ; autoc[1]+=d*data[sample+1]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi]                     ; ST = d*data[sample] d                 WATCHOUT: no displacement byte here!
+       fadd    dword [edi]                     ; ST = autoc[0]+d*data[sample] d        WATCHOUT: no displacement byte here!
+       fstp    dword [edi]                     ; autoc[0]+=d*data[sample]  ST = d      WATCHOUT: no displacement byte here!
+.jumper1_0:
+
+       fstp    st0                             ; pop d, ST = empty
+       add     esi, byte 4                     ; sample++
+       dec     ecx
+       jz      .loop1_end
+       fld     dword [esi]                     ; ST = d <- data[sample]
+       jmp     edx
+.loop1_end:
+
+       ;       for(; sample < data_len; sample++) {
+       ;               d = data[sample];
+       ;               for(coeff = 0; coeff < data_len - sample; coeff++)
+       ;                       autoc[coeff] += d * data[sample+coeff];
+       ;       }
+       mov     ecx, [esp + 24]                 ; ecx <- lag
+       dec     ecx                             ; ecx <- lag - 1
+       jz      near .end                       ; skip loop if 0 (i.e. lag == 1)
+
+       fld     dword [esi]                     ; ST = d <- data[sample]
+       mov     eax, ecx                        ; eax <- lag - 1 == data_len - sample the first time through
+       ; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+       lea     edx, [eax + eax*2]
+       neg     edx
+       lea     edx, [eax + edx*4 + .jumper2_0 - .get_eip2]
+       call    .get_eip2
+.get_eip2:
+       pop     ebx
+       add     edx, ebx
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       jmp     edx
+
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (31*4)]            ; ST = d*data[sample+31] d
+       fadd    dword [edi + (31*4)]            ; ST = autoc[31]+d*data[sample+31] d
+       fstp    dword [edi + (31*4)]            ; autoc[31]+=d*data[sample+31]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (30*4)]            ; ST = d*data[sample+30] d
+       fadd    dword [edi + (30*4)]            ; ST = autoc[30]+d*data[sample+30] d
+       fstp    dword [edi + (30*4)]            ; autoc[30]+=d*data[sample+30]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (29*4)]            ; ST = d*data[sample+29] d
+       fadd    dword [edi + (29*4)]            ; ST = autoc[29]+d*data[sample+29] d
+       fstp    dword [edi + (29*4)]            ; autoc[29]+=d*data[sample+29]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (28*4)]            ; ST = d*data[sample+28] d
+       fadd    dword [edi + (28*4)]            ; ST = autoc[28]+d*data[sample+28] d
+       fstp    dword [edi + (28*4)]            ; autoc[28]+=d*data[sample+28]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (27*4)]            ; ST = d*data[sample+27] d
+       fadd    dword [edi + (27*4)]            ; ST = autoc[27]+d*data[sample+27] d
+       fstp    dword [edi + (27*4)]            ; autoc[27]+=d*data[sample+27]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (26*4)]            ; ST = d*data[sample+26] d
+       fadd    dword [edi + (26*4)]            ; ST = autoc[26]+d*data[sample+26] d
+       fstp    dword [edi + (26*4)]            ; autoc[26]+=d*data[sample+26]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (25*4)]            ; ST = d*data[sample+25] d
+       fadd    dword [edi + (25*4)]            ; ST = autoc[25]+d*data[sample+25] d
+       fstp    dword [edi + (25*4)]            ; autoc[25]+=d*data[sample+25]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (24*4)]            ; ST = d*data[sample+24] d
+       fadd    dword [edi + (24*4)]            ; ST = autoc[24]+d*data[sample+24] d
+       fstp    dword [edi + (24*4)]            ; autoc[24]+=d*data[sample+24]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (23*4)]            ; ST = d*data[sample+23] d
+       fadd    dword [edi + (23*4)]            ; ST = autoc[23]+d*data[sample+23] d
+       fstp    dword [edi + (23*4)]            ; autoc[23]+=d*data[sample+23]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (22*4)]            ; ST = d*data[sample+22] d
+       fadd    dword [edi + (22*4)]            ; ST = autoc[22]+d*data[sample+22] d
+       fstp    dword [edi + (22*4)]            ; autoc[22]+=d*data[sample+22]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (21*4)]            ; ST = d*data[sample+21] d
+       fadd    dword [edi + (21*4)]            ; ST = autoc[21]+d*data[sample+21] d
+       fstp    dword [edi + (21*4)]            ; autoc[21]+=d*data[sample+21]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (20*4)]            ; ST = d*data[sample+20] d
+       fadd    dword [edi + (20*4)]            ; ST = autoc[20]+d*data[sample+20] d
+       fstp    dword [edi + (20*4)]            ; autoc[20]+=d*data[sample+20]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (19*4)]            ; ST = d*data[sample+19] d
+       fadd    dword [edi + (19*4)]            ; ST = autoc[19]+d*data[sample+19] d
+       fstp    dword [edi + (19*4)]            ; autoc[19]+=d*data[sample+19]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (18*4)]            ; ST = d*data[sample+18] d
+       fadd    dword [edi + (18*4)]            ; ST = autoc[18]+d*data[sample+18] d
+       fstp    dword [edi + (18*4)]            ; autoc[18]+=d*data[sample+18]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (17*4)]            ; ST = d*data[sample+17] d
+       fadd    dword [edi + (17*4)]            ; ST = autoc[17]+d*data[sample+17] d
+       fstp    dword [edi + (17*4)]            ; autoc[17]+=d*data[sample+17]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (16*4)]            ; ST = d*data[sample+16] d
+       fadd    dword [edi + (16*4)]            ; ST = autoc[16]+d*data[sample+16] d
+       fstp    dword [edi + (16*4)]            ; autoc[16]+=d*data[sample+16]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (15*4)]            ; ST = d*data[sample+15] d
+       fadd    dword [edi + (15*4)]            ; ST = autoc[15]+d*data[sample+15] d
+       fstp    dword [edi + (15*4)]            ; autoc[15]+=d*data[sample+15]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (14*4)]            ; ST = d*data[sample+14] d
+       fadd    dword [edi + (14*4)]            ; ST = autoc[14]+d*data[sample+14] d
+       fstp    dword [edi + (14*4)]            ; autoc[14]+=d*data[sample+14]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (13*4)]            ; ST = d*data[sample+13] d
+       fadd    dword [edi + (13*4)]            ; ST = autoc[13]+d*data[sample+13] d
+       fstp    dword [edi + (13*4)]            ; autoc[13]+=d*data[sample+13]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (12*4)]            ; ST = d*data[sample+12] d
+       fadd    dword [edi + (12*4)]            ; ST = autoc[12]+d*data[sample+12] d
+       fstp    dword [edi + (12*4)]            ; autoc[12]+=d*data[sample+12]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (11*4)]            ; ST = d*data[sample+11] d
+       fadd    dword [edi + (11*4)]            ; ST = autoc[11]+d*data[sample+11] d
+       fstp    dword [edi + (11*4)]            ; autoc[11]+=d*data[sample+11]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + (10*4)]            ; ST = d*data[sample+10] d
+       fadd    dword [edi + (10*4)]            ; ST = autoc[10]+d*data[sample+10] d
+       fstp    dword [edi + (10*4)]            ; autoc[10]+=d*data[sample+10]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 9*4)]            ; ST = d*data[sample+9] d
+       fadd    dword [edi + ( 9*4)]            ; ST = autoc[9]+d*data[sample+9] d
+       fstp    dword [edi + ( 9*4)]            ; autoc[9]+=d*data[sample+9]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 8*4)]            ; ST = d*data[sample+8] d
+       fadd    dword [edi + ( 8*4)]            ; ST = autoc[8]+d*data[sample+8] d
+       fstp    dword [edi + ( 8*4)]            ; autoc[8]+=d*data[sample+8]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 7*4)]            ; ST = d*data[sample+7] d
+       fadd    dword [edi + ( 7*4)]            ; ST = autoc[7]+d*data[sample+7] d
+       fstp    dword [edi + ( 7*4)]            ; autoc[7]+=d*data[sample+7]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 6*4)]            ; ST = d*data[sample+6] d
+       fadd    dword [edi + ( 6*4)]            ; ST = autoc[6]+d*data[sample+6] d
+       fstp    dword [edi + ( 6*4)]            ; autoc[6]+=d*data[sample+6]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 5*4)]            ; ST = d*data[sample+4] d
+       fadd    dword [edi + ( 5*4)]            ; ST = autoc[4]+d*data[sample+4] d
+       fstp    dword [edi + ( 5*4)]            ; autoc[4]+=d*data[sample+4]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 4*4)]            ; ST = d*data[sample+4] d
+       fadd    dword [edi + ( 4*4)]            ; ST = autoc[4]+d*data[sample+4] d
+       fstp    dword [edi + ( 4*4)]            ; autoc[4]+=d*data[sample+4]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 3*4)]            ; ST = d*data[sample+3] d
+       fadd    dword [edi + ( 3*4)]            ; ST = autoc[3]+d*data[sample+3] d
+       fstp    dword [edi + ( 3*4)]            ; autoc[3]+=d*data[sample+3]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 2*4)]            ; ST = d*data[sample+2] d
+       fadd    dword [edi + ( 2*4)]            ; ST = autoc[2]+d*data[sample+2] d
+       fstp    dword [edi + ( 2*4)]            ; autoc[2]+=d*data[sample+2]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi + ( 1*4)]            ; ST = d*data[sample+1] d
+       fadd    dword [edi + ( 1*4)]            ; ST = autoc[1]+d*data[sample+1] d
+       fstp    dword [edi + ( 1*4)]            ; autoc[1]+=d*data[sample+1]  ST = d
+       fld     st0                             ; ST = d d
+       fmul    dword [esi]                     ; ST = d*data[sample] d                 WATCHOUT: no displacement byte here!
+       fadd    dword [edi]                     ; ST = autoc[0]+d*data[sample] d        WATCHOUT: no displacement byte here!
+       fstp    dword [edi]                     ; autoc[0]+=d*data[sample]  ST = d      WATCHOUT: no displacement byte here!
+.jumper2_0:
+
+       fstp    st0                             ; pop d, ST = empty
+       add     esi, byte 4                     ; sample++
+       dec     ecx
+       jz      .loop2_end
+       add     edx, byte 11                    ; adjust our inner loop counter by adjusting the jump target
+       fld     dword [esi]                     ; ST = d <- data[sample]
+       jmp     edx
+.loop2_end:
+
+.end:
+       pop     ebx
+       pop     edi
+       pop     esi
+       ret
+
+       ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4
+       ;[esp + 16] == autoc[]
+       ;[esp + 12] == lag
+       ;[esp + 8] == data_len
+       ;[esp + 4] == data[]
+
+       ;ASSERT(lag > 0)
+       ;ASSERT(lag <= 4)
+       ;ASSERT(lag <= data_len)
+
+       ;       for(coeff = 0; coeff < lag; coeff++)
+       ;               autoc[coeff] = 0.0;
+       xorps   xmm5, xmm5
+
+       mov     edx, [esp + 8]                  ; edx == data_len
+       mov     eax, [esp + 4]                  ; eax == &data[sample] <- &data[0]
+
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[0]
+       add     eax, 4
+       movaps  xmm2, xmm0                      ; xmm2 = 0,0,0,data[0]
+       shufps  xmm0, xmm0, 0                   ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+.warmup:                                       ; xmm2 == data[sample-3],data[sample-2],data[sample-1],data[sample]
+       mulps   xmm0, xmm2                      ; xmm0 = xmm0 * xmm2
+       addps   xmm5, xmm0                      ; xmm5 += xmm0 * xmm2
+       dec     edx
+       jz      .loop_end
+       ALIGN 16
+.loop_start:
+       ; start by reading the next sample
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[sample]
+       add     eax, 4
+       shufps  xmm0, xmm0, 0                   ; xmm0 = data[sample],data[sample],data[sample],data[sample]
+       shufps  xmm2, xmm2, 93h                 ; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+       movss   xmm2, xmm0
+       mulps   xmm0, xmm2                      ; xmm0 = xmm0 * xmm2
+       addps   xmm5, xmm0                      ; xmm5 += xmm0 * xmm2
+       dec     edx
+       jnz     .loop_start
+.loop_end:
+       ; store autoc
+       mov     edx, [esp + 16]                 ; edx == autoc
+       movups  [edx], xmm5
+
+.end:
+       ret
+
+       ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8
+       ;[esp + 16] == autoc[]
+       ;[esp + 12] == lag
+       ;[esp + 8] == data_len
+       ;[esp + 4] == data[]
+
+       ;ASSERT(lag > 0)
+       ;ASSERT(lag <= 8)
+       ;ASSERT(lag <= data_len)
+
+       ;       for(coeff = 0; coeff < lag; coeff++)
+       ;               autoc[coeff] = 0.0;
+       xorps   xmm5, xmm5
+       xorps   xmm6, xmm6
+
+       mov     edx, [esp + 8]                  ; edx == data_len
+       mov     eax, [esp + 4]                  ; eax == &data[sample] <- &data[0]
+
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[0]
+       add     eax, 4
+       movaps  xmm2, xmm0                      ; xmm2 = 0,0,0,data[0]
+       shufps  xmm0, xmm0, 0                   ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+       movaps  xmm1, xmm0                      ; xmm1 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+       xorps   xmm3, xmm3                      ; xmm3 = 0,0,0,0
+.warmup:                                       ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+       mulps   xmm0, xmm2
+       mulps   xmm1, xmm3                      ; xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+       addps   xmm5, xmm0
+       addps   xmm6, xmm1                      ; xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+       dec     edx
+       jz      .loop_end
+       ALIGN 16
+.loop_start:
+       ; start by reading the next sample
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[sample]
+       ; here we reorder the instructions; see the (#) indexes for a logical order
+       shufps  xmm2, xmm2, 93h                 ; (3) 93h=2-1-0-3 => xmm2 gets rotated left by one float
+       add     eax, 4                          ; (0)
+       shufps  xmm3, xmm3, 93h                 ; (4) 93h=2-1-0-3 => xmm3 gets rotated left by one float
+       shufps  xmm0, xmm0, 0                   ; (1) xmm0 = data[sample],data[sample],data[sample],data[sample]
+       movss   xmm3, xmm2                      ; (5)
+       movaps  xmm1, xmm0                      ; (2) xmm1 = data[sample],data[sample],data[sample],data[sample]
+       movss   xmm2, xmm0                      ; (6)
+       mulps   xmm1, xmm3                      ; (8)
+       mulps   xmm0, xmm2                      ; (7) xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+       addps   xmm6, xmm1                      ; (10)
+       addps   xmm5, xmm0                      ; (9) xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+       dec     edx
+       jnz     .loop_start
+.loop_end:
+       ; store autoc
+       mov     edx, [esp + 16]                 ; edx == autoc
+       movups  [edx], xmm5
+       movups  [edx + 16], xmm6
+
+.end:
+       ret
+
+       ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12
+       ;[esp + 16] == autoc[]
+       ;[esp + 12] == lag
+       ;[esp + 8] == data_len
+       ;[esp + 4] == data[]
+
+       ;ASSERT(lag > 0)
+       ;ASSERT(lag <= 12)
+       ;ASSERT(lag <= data_len)
+
+       ;       for(coeff = 0; coeff < lag; coeff++)
+       ;               autoc[coeff] = 0.0;
+       xorps   xmm5, xmm5
+       xorps   xmm6, xmm6
+       xorps   xmm7, xmm7
+
+       mov     edx, [esp + 8]                  ; edx == data_len
+       mov     eax, [esp + 4]                  ; eax == &data[sample] <- &data[0]
+
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[0]
+       add     eax, 4
+       movaps  xmm2, xmm0                      ; xmm2 = 0,0,0,data[0]
+       shufps  xmm0, xmm0, 0                   ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+       xorps   xmm3, xmm3                      ; xmm3 = 0,0,0,0
+       xorps   xmm4, xmm4                      ; xmm4 = 0,0,0,0
+.warmup:                                       ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+       movaps  xmm1, xmm0
+       mulps   xmm1, xmm2
+       addps   xmm5, xmm1
+       movaps  xmm1, xmm0
+       mulps   xmm1, xmm3
+       addps   xmm6, xmm1
+       mulps   xmm0, xmm4
+       addps   xmm7, xmm0                      ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2
+       dec     edx
+       jz      .loop_end
+       ALIGN 16
+.loop_start:
+       ; start by reading the next sample
+       movss   xmm0, [eax]                     ; xmm0 = 0,0,0,data[sample]
+       add     eax, 4
+       shufps  xmm0, xmm0, 0                   ; xmm0 = data[sample],data[sample],data[sample],data[sample]
+
+       ; shift xmm4:xmm3:xmm2 left by one float
+       shufps  xmm2, xmm2, 93h                 ; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+       shufps  xmm3, xmm3, 93h                 ; 93h=2-1-0-3 => xmm3 gets rotated left by one float
+       shufps  xmm4, xmm4, 93h                 ; 93h=2-1-0-3 => xmm4 gets rotated left by one float
+       movss   xmm4, xmm3
+       movss   xmm3, xmm2
+       movss   xmm2, xmm0
+
+       ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm3:xmm3:xmm2
+       movaps  xmm1, xmm0
+       mulps   xmm1, xmm2
+       addps   xmm5, xmm1
+       movaps  xmm1, xmm0
+       mulps   xmm1, xmm3
+       addps   xmm6, xmm1
+       mulps   xmm0, xmm4
+       addps   xmm7, xmm0
+
+       dec     edx
+       jnz     .loop_start
+.loop_end:
+       ; store autoc
+       mov     edx, [esp + 16]                 ; edx == autoc
+       movups  [edx], xmm5
+       movups  [edx + 16], xmm6
+       movups  [edx + 32], xmm7
+
+.end:
+       ret
+
+       ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow
+       ;[ebp + 32] autoc
+       ;[ebp + 28] lag
+       ;[ebp + 24] data_len
+       ;[ebp + 20] data
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+       mov     ebp, esp
+
+       mov     esi, [ebp + 20]
+       mov     edi, [ebp + 24]
+       mov     edx, [ebp + 28]
+       inc     edx
+       and     edx, byte -2
+       mov     eax, edx
+       neg     eax
+       and     esp, byte -8
+       lea     esp, [esp + 4 * eax]
+       mov     ecx, edx
+       xor     eax, eax
+.loop0:
+       dec     ecx
+       mov     [esp + 4 * ecx], eax
+       jnz     short .loop0
+
+       mov     eax, edi
+       sub     eax, edx
+       mov     ebx, edx
+       and     ebx, byte 1
+       sub     eax, ebx
+       lea     ecx, [esi + 4 * eax - 12]
+       cmp     esi, ecx
+       mov     eax, esi
+       ja      short .loop2_pre
+       ALIGN   16              ;4 nops
+.loop1_i:
+       movd    mm0, [eax]
+       movd    mm2, [eax + 4]
+       movd    mm4, [eax + 8]
+       movd    mm6, [eax + 12]
+       mov     ebx, edx
+       punpckldq       mm0, mm0
+       punpckldq       mm2, mm2
+       punpckldq       mm4, mm4
+       punpckldq       mm6, mm6
+       ALIGN   16              ;3 nops
+.loop1_j:
+       sub     ebx, byte 2
+       movd    mm1, [eax + 4 * ebx]
+       movd    mm3, [eax + 4 * ebx + 4]
+       movd    mm5, [eax + 4 * ebx + 8]
+       movd    mm7, [eax + 4 * ebx + 12]
+       punpckldq       mm1, mm3
+       punpckldq       mm3, mm5
+       pfmul   mm1, mm0
+       punpckldq       mm5, mm7
+       pfmul   mm3, mm2
+       punpckldq       mm7, [eax + 4 * ebx + 16]
+       pfmul   mm5, mm4
+       pfmul   mm7, mm6
+       pfadd   mm1, mm3
+       movq    mm3, [esp + 4 * ebx]
+       pfadd   mm5, mm7
+       pfadd   mm1, mm5
+       pfadd   mm3, mm1
+       movq    [esp + 4 * ebx], mm3
+       jg      short .loop1_j
+
+       add     eax, byte 16
+       cmp     eax, ecx
+       jb      short .loop1_i
+
+.loop2_pre:
+       mov     ebx, eax
+       sub     eax, esi
+       shr     eax, 2
+       lea     ecx, [esi + 4 * edi]
+       mov     esi, ebx
+.loop2_i:
+       movd    mm0, [esi]
+       mov     ebx, edi
+       sub     ebx, eax
+       cmp     ebx, edx
+       jbe     short .loop2_j
+       mov     ebx, edx
+.loop2_j:
+       dec     ebx
+       movd    mm1, [esi + 4 * ebx]
+       pfmul   mm1, mm0
+       movd    mm2, [esp + 4 * ebx]
+       pfadd   mm1, mm2
+       movd    [esp + 4 * ebx], mm1
+
+       jnz     short .loop2_j
+
+       add     esi, byte 4
+       inc     eax
+       cmp     esi, ecx
+       jnz     short .loop2_i
+
+       mov     edi, [ebp + 32]
+       mov     edx, [ebp + 28]
+.loop3:
+       dec     edx
+       mov     eax, [esp + 4 * edx]
+       mov     [edi + 4 * edx], eax
+       jnz     short .loop3
+
+       femms
+
+       mov     esp, ebp
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+;void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+;
+;      for(i = 0; i < data_len; i++) {
+;              sum = 0;
+;              for(j = 0; j < order; j++)
+;                      sum += qlp_coeff[j] * data[i-j-1];
+;              residual[i] = data[i] - (sum >> lp_quantization);
+;      }
+;
+       ALIGN   16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+       ;[esp + 40]     residual[]
+       ;[esp + 36]     lp_quantization
+       ;[esp + 32]     order
+       ;[esp + 28]     qlp_coeff[]
+       ;[esp + 24]     data_len
+       ;[esp + 20]     data[]
+
+       ;ASSERT(order > 0)
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+
+       mov     esi, [esp + 20]                 ; esi = data[]
+       mov     edi, [esp + 40]                 ; edi = residual[]
+       mov     eax, [esp + 32]                 ; eax = order
+       mov     ebx, [esp + 24]                 ; ebx = data_len
+
+       test    ebx, ebx
+       jz      near .end                       ; do nothing if data_len == 0
+.begin:
+       cmp     eax, byte 1
+       jg      short .i_1more
+
+       mov     ecx, [esp + 28]
+       mov     edx, [ecx]                      ; edx = qlp_coeff[0]
+       mov     eax, [esi - 4]                  ; eax = data[-1]
+       mov     cl, [esp + 36]                  ; cl = lp_quantization
+       ALIGN   16
+.i_1_loop_i:
+       imul    eax, edx
+       sar     eax, cl
+       neg     eax
+       add     eax, [esi]
+       mov     [edi], eax
+       mov     eax, [esi]
+       add     edi, byte 4
+       add     esi, byte 4
+       dec     ebx
+       jnz     .i_1_loop_i
+
+       jmp     .end
+
+.i_1more:
+       cmp     eax, byte 32                    ; for order <= 32 there is a faster routine
+       jbe     short .i_32
+
+       ; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+       ALIGN 16
+.i_32more_loop_i:
+       xor     ebp, ebp
+       mov     ecx, [esp + 32]
+       mov     edx, ecx
+       shl     edx, 2
+       add     edx, [esp + 28]
+       neg     ecx
+       ALIGN   16
+.i_32more_loop_j:
+       sub     edx, byte 4
+       mov     eax, [edx]
+       imul    eax, [esi + 4 * ecx]
+       add     ebp, eax
+       inc     ecx
+       jnz     short .i_32more_loop_j
+
+       mov     cl, [esp + 36]
+       sar     ebp, cl
+       neg     ebp
+       add     ebp, [esi]
+       mov     [edi], ebp
+       add     esi, byte 4
+       add     edi, byte 4
+
+       dec     ebx
+       jnz     .i_32more_loop_i
+
+       jmp     .end
+
+.i_32:
+       sub     edi, esi
+       neg     eax
+       lea     edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+       call    .get_eip0
+.get_eip0:
+       pop     eax
+       add     edx, eax
+       inc     edx
+       mov     eax, [esp + 28]                 ; eax = qlp_coeff[]
+       xor     ebp, ebp
+       jmp     edx
+
+       mov     ecx, [eax + 124]
+       imul    ecx, [esi - 128]
+       add     ebp, ecx
+       mov     ecx, [eax + 120]
+       imul    ecx, [esi - 124]
+       add     ebp, ecx
+       mov     ecx, [eax + 116]
+       imul    ecx, [esi - 120]
+       add     ebp, ecx
+       mov     ecx, [eax + 112]
+       imul    ecx, [esi - 116]
+       add     ebp, ecx
+       mov     ecx, [eax + 108]
+       imul    ecx, [esi - 112]
+       add     ebp, ecx
+       mov     ecx, [eax + 104]
+       imul    ecx, [esi - 108]
+       add     ebp, ecx
+       mov     ecx, [eax + 100]
+       imul    ecx, [esi - 104]
+       add     ebp, ecx
+       mov     ecx, [eax + 96]
+       imul    ecx, [esi - 100]
+       add     ebp, ecx
+       mov     ecx, [eax + 92]
+       imul    ecx, [esi - 96]
+       add     ebp, ecx
+       mov     ecx, [eax + 88]
+       imul    ecx, [esi - 92]
+       add     ebp, ecx
+       mov     ecx, [eax + 84]
+       imul    ecx, [esi - 88]
+       add     ebp, ecx
+       mov     ecx, [eax + 80]
+       imul    ecx, [esi - 84]
+       add     ebp, ecx
+       mov     ecx, [eax + 76]
+       imul    ecx, [esi - 80]
+       add     ebp, ecx
+       mov     ecx, [eax + 72]
+       imul    ecx, [esi - 76]
+       add     ebp, ecx
+       mov     ecx, [eax + 68]
+       imul    ecx, [esi - 72]
+       add     ebp, ecx
+       mov     ecx, [eax + 64]
+       imul    ecx, [esi - 68]
+       add     ebp, ecx
+       mov     ecx, [eax + 60]
+       imul    ecx, [esi - 64]
+       add     ebp, ecx
+       mov     ecx, [eax + 56]
+       imul    ecx, [esi - 60]
+       add     ebp, ecx
+       mov     ecx, [eax + 52]
+       imul    ecx, [esi - 56]
+       add     ebp, ecx
+       mov     ecx, [eax + 48]
+       imul    ecx, [esi - 52]
+       add     ebp, ecx
+       mov     ecx, [eax + 44]
+       imul    ecx, [esi - 48]
+       add     ebp, ecx
+       mov     ecx, [eax + 40]
+       imul    ecx, [esi - 44]
+       add     ebp, ecx
+       mov     ecx, [eax + 36]
+       imul    ecx, [esi - 40]
+       add     ebp, ecx
+       mov     ecx, [eax + 32]
+       imul    ecx, [esi - 36]
+       add     ebp, ecx
+       mov     ecx, [eax + 28]
+       imul    ecx, [esi - 32]
+       add     ebp, ecx
+       mov     ecx, [eax + 24]
+       imul    ecx, [esi - 28]
+       add     ebp, ecx
+       mov     ecx, [eax + 20]
+       imul    ecx, [esi - 24]
+       add     ebp, ecx
+       mov     ecx, [eax + 16]
+       imul    ecx, [esi - 20]
+       add     ebp, ecx
+       mov     ecx, [eax + 12]
+       imul    ecx, [esi - 16]
+       add     ebp, ecx
+       mov     ecx, [eax + 8]
+       imul    ecx, [esi - 12]
+       add     ebp, ecx
+       mov     ecx, [eax + 4]
+       imul    ecx, [esi - 8]
+       add     ebp, ecx
+       mov     ecx, [eax]                      ; there is one byte missing
+       imul    ecx, [esi - 4]
+       add     ebp, ecx
+.jumper_0:
+
+       mov     cl, [esp + 36]
+       sar     ebp, cl
+       neg     ebp
+       add     ebp, [esi]
+       mov     [edi + esi], ebp
+       add     esi, byte 4
+
+       dec     ebx
+       jz      short .end
+       xor     ebp, ebp
+       jmp     edx
+
+.end:
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16.  Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+       ALIGN   16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+       ;[esp + 40]     residual[]
+       ;[esp + 36]     lp_quantization
+       ;[esp + 32]     order
+       ;[esp + 28]     qlp_coeff[]
+       ;[esp + 24]     data_len
+       ;[esp + 20]     data[]
+
+       ;ASSERT(order > 0)
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+
+       mov     esi, [esp + 20]                 ; esi = data[]
+       mov     edi, [esp + 40]                 ; edi = residual[]
+       mov     eax, [esp + 32]                 ; eax = order
+       mov     ebx, [esp + 24]                 ; ebx = data_len
+
+       test    ebx, ebx
+       jz      near .end                       ; do nothing if data_len == 0
+       dec     ebx
+       test    ebx, ebx
+       jz      near .last_one
+
+       mov     edx, [esp + 28]                 ; edx = qlp_coeff[]
+       movd    mm6, [esp + 36]                 ; mm6 = 0:lp_quantization
+       mov     ebp, esp
+
+       and     esp, 0xfffffff8
+
+       xor     ecx, ecx
+.copy_qlp_loop:
+       push    word [edx + 4 * ecx]
+       inc     ecx
+       cmp     ecx, eax
+       jnz     short .copy_qlp_loop
+
+       and     ecx, 0x3
+       test    ecx, ecx
+       je      short .za_end
+       sub     ecx, byte 4
+.za_loop:
+       push    word 0
+       inc     eax
+       inc     ecx
+       jnz     short .za_loop
+.za_end:
+
+       movq    mm5, [esp + 2 * eax - 8]
+       movd    mm4, [esi - 16]
+       punpckldq       mm4, [esi - 12]
+       movd    mm0, [esi - 8]
+       punpckldq       mm0, [esi - 4]
+       packssdw        mm4, mm0
+
+       cmp     eax, byte 4
+       jnbe    short .mmx_4more
+
+       ALIGN   16
+.mmx_4_loop_i:
+       movd    mm1, [esi]
+       movq    mm3, mm4
+       punpckldq       mm1, [esi + 4]
+       psrlq   mm4, 16
+       movq    mm0, mm1
+       psllq   mm0, 48
+       por     mm4, mm0
+       movq    mm2, mm4
+       psrlq   mm4, 16
+       pxor    mm0, mm0
+       punpckhdq       mm0, mm1
+       pmaddwd mm3, mm5
+       pmaddwd mm2, mm5
+       psllq   mm0, 16
+       por     mm4, mm0
+       movq    mm0, mm3
+       punpckldq       mm3, mm2
+       punpckhdq       mm0, mm2
+       paddd   mm3, mm0
+       psrad   mm3, mm6
+       psubd   mm1, mm3
+       movd    [edi], mm1
+       punpckhdq       mm1, mm1
+       movd    [edi + 4], mm1
+
+       add     edi, byte 8
+       add     esi, byte 8
+
+       sub     ebx, 2
+       jg      .mmx_4_loop_i
+       jmp     .mmx_end
+
+.mmx_4more:
+       shl     eax, 2
+       neg     eax
+       add     eax, byte 16
+
+       ALIGN   16
+.mmx_4more_loop_i:
+       movd    mm1, [esi]
+       punpckldq       mm1, [esi + 4]
+       movq    mm3, mm4
+       psrlq   mm4, 16
+       movq    mm0, mm1
+       psllq   mm0, 48
+       por     mm4, mm0
+       movq    mm2, mm4
+       psrlq   mm4, 16
+       pxor    mm0, mm0
+       punpckhdq       mm0, mm1
+       pmaddwd mm3, mm5
+       pmaddwd mm2, mm5
+       psllq   mm0, 16
+       por     mm4, mm0
+
+       mov     ecx, esi
+       add     ecx, eax
+       mov     edx, esp
+
+       ALIGN   16
+.mmx_4more_loop_j:
+       movd    mm0, [ecx - 16]
+       movd    mm7, [ecx - 8]
+       punpckldq       mm0, [ecx - 12]
+       punpckldq       mm7, [ecx - 4]
+       packssdw        mm0, mm7
+       pmaddwd mm0, [edx]
+       punpckhdq       mm7, mm7
+       paddd   mm3, mm0
+       movd    mm0, [ecx - 12]
+       punpckldq       mm0, [ecx - 8]
+       punpckldq       mm7, [ecx]
+       packssdw        mm0, mm7
+       pmaddwd mm0, [edx]
+       paddd   mm2, mm0
+
+       add     edx, byte 8
+       add     ecx, byte 16
+       cmp     ecx, esi
+       jnz     .mmx_4more_loop_j
+
+       movq    mm0, mm3
+       punpckldq       mm3, mm2
+       punpckhdq       mm0, mm2
+       paddd   mm3, mm0
+       psrad   mm3, mm6
+       psubd   mm1, mm3
+       movd    [edi], mm1
+       punpckhdq       mm1, mm1
+       movd    [edi + 4], mm1
+
+       add     edi, byte 8
+       add     esi, byte 8
+
+       sub     ebx, 2
+       jg      near .mmx_4more_loop_i
+
+.mmx_end:
+       emms
+       mov     esp, ebp
+.last_one:
+       mov     eax, [esp + 32]
+       inc     ebx
+       jnz     near FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32.begin
+
+.end:
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+; **********************************************************************
+;
+; void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+; {
+;      unsigned i, j;
+;      FLAC__int32 sum;
+;
+;      FLAC__ASSERT(order > 0);
+;
+;      for(i = 0; i < data_len; i++) {
+;              sum = 0;
+;              for(j = 0; j < order; j++)
+;                      sum += qlp_coeff[j] * data[i-j-1];
+;              data[i] = residual[i] + (sum >> lp_quantization);
+;      }
+; }
+       ALIGN   16
+cident FLAC__lpc_restore_signal_asm_ia32
+       ;[esp + 40]     data[]
+       ;[esp + 36]     lp_quantization
+       ;[esp + 32]     order
+       ;[esp + 28]     qlp_coeff[]
+       ;[esp + 24]     data_len
+       ;[esp + 20]     residual[]
+
+       ;ASSERT(order > 0)
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+
+       mov     esi, [esp + 20]                 ; esi = residual[]
+       mov     edi, [esp + 40]                 ; edi = data[]
+       mov     eax, [esp + 32]                 ; eax = order
+       mov     ebx, [esp + 24]                 ; ebx = data_len
+
+       test    ebx, ebx
+       jz      near .end                       ; do nothing if data_len == 0
+
+.begin:
+       cmp     eax, byte 1
+       jg      short .x87_1more
+
+       mov     ecx, [esp + 28]
+       mov     edx, [ecx]
+       mov     eax, [edi - 4]
+       mov     cl, [esp + 36]
+       ALIGN   16
+.x87_1_loop_i:
+       imul    eax, edx
+       sar     eax, cl
+       add     eax, [esi]
+       mov     [edi], eax
+       add     esi, byte 4
+       add     edi, byte 4
+       dec     ebx
+       jnz     .x87_1_loop_i
+
+       jmp     .end
+
+.x87_1more:
+       cmp     eax, byte 32                    ; for order <= 32 there is a faster routine
+       jbe     short .x87_32
+
+       ; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+       ALIGN 16
+.x87_32more_loop_i:
+       xor     ebp, ebp
+       mov     ecx, [esp + 32]
+       mov     edx, ecx
+       shl     edx, 2
+       add     edx, [esp + 28]
+       neg     ecx
+       ALIGN   16
+.x87_32more_loop_j:
+       sub     edx, byte 4
+       mov     eax, [edx]
+       imul    eax, [edi + 4 * ecx]
+       add     ebp, eax
+       inc     ecx
+       jnz     short .x87_32more_loop_j
+
+       mov     cl, [esp + 36]
+       sar     ebp, cl
+       add     ebp, [esi]
+       mov     [edi], ebp
+       add     edi, byte 4
+       add     esi, byte 4
+
+       dec     ebx
+       jnz     .x87_32more_loop_i
+
+       jmp     .end
+
+.x87_32:
+       sub     esi, edi
+       neg     eax
+       lea     edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+       call    .get_eip0
+.get_eip0:
+       pop     eax
+       add     edx, eax
+       inc     edx                             ; compensate for the shorter opcode on the last iteration
+       mov     eax, [esp + 28]                 ; eax = qlp_coeff[]
+       xor     ebp, ebp
+       jmp     edx
+
+       mov     ecx, [eax + 124]                ; ecx =  qlp_coeff[31]
+       imul    ecx, [edi - 128]                ; ecx =  qlp_coeff[31] * data[i-32]
+       add     ebp, ecx                        ; sum += qlp_coeff[31] * data[i-32]
+       mov     ecx, [eax + 120]                ; ecx =  qlp_coeff[30]
+       imul    ecx, [edi - 124]                ; ecx =  qlp_coeff[30] * data[i-31]
+       add     ebp, ecx                        ; sum += qlp_coeff[30] * data[i-31]
+       mov     ecx, [eax + 116]                ; ecx =  qlp_coeff[29]
+       imul    ecx, [edi - 120]                ; ecx =  qlp_coeff[29] * data[i-30]
+       add     ebp, ecx                        ; sum += qlp_coeff[29] * data[i-30]
+       mov     ecx, [eax + 112]                ; ecx =  qlp_coeff[28]
+       imul    ecx, [edi - 116]                ; ecx =  qlp_coeff[28] * data[i-29]
+       add     ebp, ecx                        ; sum += qlp_coeff[28] * data[i-29]
+       mov     ecx, [eax + 108]                ; ecx =  qlp_coeff[27]
+       imul    ecx, [edi - 112]                ; ecx =  qlp_coeff[27] * data[i-28]
+       add     ebp, ecx                        ; sum += qlp_coeff[27] * data[i-28]
+       mov     ecx, [eax + 104]                ; ecx =  qlp_coeff[26]
+       imul    ecx, [edi - 108]                ; ecx =  qlp_coeff[26] * data[i-27]
+       add     ebp, ecx                        ; sum += qlp_coeff[26] * data[i-27]
+       mov     ecx, [eax + 100]                ; ecx =  qlp_coeff[25]
+       imul    ecx, [edi - 104]                ; ecx =  qlp_coeff[25] * data[i-26]
+       add     ebp, ecx                        ; sum += qlp_coeff[25] * data[i-26]
+       mov     ecx, [eax + 96]                 ; ecx =  qlp_coeff[24]
+       imul    ecx, [edi - 100]                ; ecx =  qlp_coeff[24] * data[i-25]
+       add     ebp, ecx                        ; sum += qlp_coeff[24] * data[i-25]
+       mov     ecx, [eax + 92]                 ; ecx =  qlp_coeff[23]
+       imul    ecx, [edi - 96]                 ; ecx =  qlp_coeff[23] * data[i-24]
+       add     ebp, ecx                        ; sum += qlp_coeff[23] * data[i-24]
+       mov     ecx, [eax + 88]                 ; ecx =  qlp_coeff[22]
+       imul    ecx, [edi - 92]                 ; ecx =  qlp_coeff[22] * data[i-23]
+       add     ebp, ecx                        ; sum += qlp_coeff[22] * data[i-23]
+       mov     ecx, [eax + 84]                 ; ecx =  qlp_coeff[21]
+       imul    ecx, [edi - 88]                 ; ecx =  qlp_coeff[21] * data[i-22]
+       add     ebp, ecx                        ; sum += qlp_coeff[21] * data[i-22]
+       mov     ecx, [eax + 80]                 ; ecx =  qlp_coeff[20]
+       imul    ecx, [edi - 84]                 ; ecx =  qlp_coeff[20] * data[i-21]
+       add     ebp, ecx                        ; sum += qlp_coeff[20] * data[i-21]
+       mov     ecx, [eax + 76]                 ; ecx =  qlp_coeff[19]
+       imul    ecx, [edi - 80]                 ; ecx =  qlp_coeff[19] * data[i-20]
+       add     ebp, ecx                        ; sum += qlp_coeff[19] * data[i-20]
+       mov     ecx, [eax + 72]                 ; ecx =  qlp_coeff[18]
+       imul    ecx, [edi - 76]                 ; ecx =  qlp_coeff[18] * data[i-19]
+       add     ebp, ecx                        ; sum += qlp_coeff[18] * data[i-19]
+       mov     ecx, [eax + 68]                 ; ecx =  qlp_coeff[17]
+       imul    ecx, [edi - 72]                 ; ecx =  qlp_coeff[17] * data[i-18]
+       add     ebp, ecx                        ; sum += qlp_coeff[17] * data[i-18]
+       mov     ecx, [eax + 64]                 ; ecx =  qlp_coeff[16]
+       imul    ecx, [edi - 68]                 ; ecx =  qlp_coeff[16] * data[i-17]
+       add     ebp, ecx                        ; sum += qlp_coeff[16] * data[i-17]
+       mov     ecx, [eax + 60]                 ; ecx =  qlp_coeff[15]
+       imul    ecx, [edi - 64]                 ; ecx =  qlp_coeff[15] * data[i-16]
+       add     ebp, ecx                        ; sum += qlp_coeff[15] * data[i-16]
+       mov     ecx, [eax + 56]                 ; ecx =  qlp_coeff[14]
+       imul    ecx, [edi - 60]                 ; ecx =  qlp_coeff[14] * data[i-15]
+       add     ebp, ecx                        ; sum += qlp_coeff[14] * data[i-15]
+       mov     ecx, [eax + 52]                 ; ecx =  qlp_coeff[13]
+       imul    ecx, [edi - 56]                 ; ecx =  qlp_coeff[13] * data[i-14]
+       add     ebp, ecx                        ; sum += qlp_coeff[13] * data[i-14]
+       mov     ecx, [eax + 48]                 ; ecx =  qlp_coeff[12]
+       imul    ecx, [edi - 52]                 ; ecx =  qlp_coeff[12] * data[i-13]
+       add     ebp, ecx                        ; sum += qlp_coeff[12] * data[i-13]
+       mov     ecx, [eax + 44]                 ; ecx =  qlp_coeff[11]
+       imul    ecx, [edi - 48]                 ; ecx =  qlp_coeff[11] * data[i-12]
+       add     ebp, ecx                        ; sum += qlp_coeff[11] * data[i-12]
+       mov     ecx, [eax + 40]                 ; ecx =  qlp_coeff[10]
+       imul    ecx, [edi - 44]                 ; ecx =  qlp_coeff[10] * data[i-11]
+       add     ebp, ecx                        ; sum += qlp_coeff[10] * data[i-11]
+       mov     ecx, [eax + 36]                 ; ecx =  qlp_coeff[ 9]
+       imul    ecx, [edi - 40]                 ; ecx =  qlp_coeff[ 9] * data[i-10]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 9] * data[i-10]
+       mov     ecx, [eax + 32]                 ; ecx =  qlp_coeff[ 8]
+       imul    ecx, [edi - 36]                 ; ecx =  qlp_coeff[ 8] * data[i- 9]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 8] * data[i- 9]
+       mov     ecx, [eax + 28]                 ; ecx =  qlp_coeff[ 7]
+       imul    ecx, [edi - 32]                 ; ecx =  qlp_coeff[ 7] * data[i- 8]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 7] * data[i- 8]
+       mov     ecx, [eax + 24]                 ; ecx =  qlp_coeff[ 6]
+       imul    ecx, [edi - 28]                 ; ecx =  qlp_coeff[ 6] * data[i- 7]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 6] * data[i- 7]
+       mov     ecx, [eax + 20]                 ; ecx =  qlp_coeff[ 5]
+       imul    ecx, [edi - 24]                 ; ecx =  qlp_coeff[ 5] * data[i- 6]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 5] * data[i- 6]
+       mov     ecx, [eax + 16]                 ; ecx =  qlp_coeff[ 4]
+       imul    ecx, [edi - 20]                 ; ecx =  qlp_coeff[ 4] * data[i- 5]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 4] * data[i- 5]
+       mov     ecx, [eax + 12]                 ; ecx =  qlp_coeff[ 3]
+       imul    ecx, [edi - 16]                 ; ecx =  qlp_coeff[ 3] * data[i- 4]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 3] * data[i- 4]
+       mov     ecx, [eax + 8]                  ; ecx =  qlp_coeff[ 2]
+       imul    ecx, [edi - 12]                 ; ecx =  qlp_coeff[ 2] * data[i- 3]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 2] * data[i- 3]
+       mov     ecx, [eax + 4]                  ; ecx =  qlp_coeff[ 1]
+       imul    ecx, [edi - 8]                  ; ecx =  qlp_coeff[ 1] * data[i- 2]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 1] * data[i- 2]
+       mov     ecx, [eax]                      ; ecx =  qlp_coeff[ 0] (NOTE: one byte missing from instruction)
+       imul    ecx, [edi - 4]                  ; ecx =  qlp_coeff[ 0] * data[i- 1]
+       add     ebp, ecx                        ; sum += qlp_coeff[ 0] * data[i- 1]
+.jumper_0:
+
+       mov     cl, [esp + 36]
+       sar     ebp, cl                         ; ebp = (sum >> lp_quantization)
+       add     ebp, [esi + edi]                ; ebp = residual[i] + (sum >> lp_quantization)
+       mov     [edi], ebp                      ; data[i] = residual[i] + (sum >> lp_quantization)
+       add     edi, byte 4
+
+       dec     ebx
+       jz      short .end
+       xor     ebp, ebp
+       jmp     edx
+
+.end:
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16.  Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+; WATCHOUT: this routine requires that each data array have a buffer of up to
+; 3 zeroes in front (at negative indices) for alignment purposes, i.e. for each
+; channel n, data[n][-1] through data[n][-3] should be accessible and zero.
+       ALIGN   16
+cident FLAC__lpc_restore_signal_asm_ia32_mmx
+       ;[esp + 40]     data[]
+       ;[esp + 36]     lp_quantization
+       ;[esp + 32]     order
+       ;[esp + 28]     qlp_coeff[]
+       ;[esp + 24]     data_len
+       ;[esp + 20]     residual[]
+
+       ;ASSERT(order > 0)
+
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+
+       mov     esi, [esp + 20]
+       mov     edi, [esp + 40]
+       mov     eax, [esp + 32]
+       mov     ebx, [esp + 24]
+
+       test    ebx, ebx
+       jz      near .end                       ; do nothing if data_len == 0
+       cmp     eax, byte 4
+       jb      near FLAC__lpc_restore_signal_asm_ia32.begin
+
+       mov     edx, [esp + 28]
+       movd    mm6, [esp + 36]
+       mov     ebp, esp
+
+       and     esp, 0xfffffff8
+
+       xor     ecx, ecx
+.copy_qlp_loop:
+       push    word [edx + 4 * ecx]
+       inc     ecx
+       cmp     ecx, eax
+       jnz     short .copy_qlp_loop
+
+       and     ecx, 0x3
+       test    ecx, ecx
+       je      short .za_end
+       sub     ecx, byte 4
+.za_loop:
+       push    word 0
+       inc     eax
+       inc     ecx
+       jnz     short .za_loop
+.za_end:
+
+       movq    mm5, [esp + 2 * eax - 8]
+       movd    mm4, [edi - 16]
+       punpckldq       mm4, [edi - 12]
+       movd    mm0, [edi - 8]
+       punpckldq       mm0, [edi - 4]
+       packssdw        mm4, mm0
+
+       cmp     eax, byte 4
+       jnbe    short .mmx_4more
+
+       ALIGN   16
+.mmx_4_loop_i:
+       movq    mm7, mm4
+       pmaddwd mm7, mm5
+       movq    mm0, mm7
+       punpckhdq       mm7, mm7
+       paddd   mm7, mm0
+       psrad   mm7, mm6
+       movd    mm1, [esi]
+       paddd   mm7, mm1
+       movd    [edi], mm7
+       psllq   mm7, 48
+       psrlq   mm4, 16
+       por     mm4, mm7
+
+       add     esi, byte 4
+       add     edi, byte 4
+
+       dec     ebx
+       jnz     .mmx_4_loop_i
+       jmp     .mmx_end
+.mmx_4more:
+       shl     eax, 2
+       neg     eax
+       add     eax, byte 16
+       ALIGN   16
+.mmx_4more_loop_i:
+       mov     ecx, edi
+       add     ecx, eax
+       mov     edx, esp
+
+       movq    mm7, mm4
+       pmaddwd mm7, mm5
+
+       ALIGN   16
+.mmx_4more_loop_j:
+       movd    mm0, [ecx - 16]
+       punpckldq       mm0, [ecx - 12]
+       movd    mm1, [ecx - 8]
+       punpckldq       mm1, [ecx - 4]
+       packssdw        mm0, mm1
+       pmaddwd mm0, [edx]
+       paddd   mm7, mm0
+
+       add     edx, byte 8
+       add     ecx, byte 16
+       cmp     ecx, edi
+       jnz     .mmx_4more_loop_j
+
+       movq    mm0, mm7
+       punpckhdq       mm7, mm7
+       paddd   mm7, mm0
+       psrad   mm7, mm6
+       movd    mm1, [esi]
+       paddd   mm7, mm1
+       movd    [edi], mm7
+       psllq   mm7, 48
+       psrlq   mm4, 16
+       por     mm4, mm7
+
+       add     esi, byte 4
+       add     edi, byte 4
+
+       dec     ebx
+       jnz     short .mmx_4more_loop_i
+.mmx_end:
+       emms
+       mov     esp, ebp
+
+.end:
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+       section .note.GNU-stack noalloc
+%endif
diff --git a/src/libFLAC/ia32/nasm.h b/src/libFLAC/ia32/nasm.h
new file mode 100644 (file)
index 0000000..215498d
--- /dev/null
@@ -0,0 +1,75 @@
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       bits 32
+
+%ifdef OBJ_FORMAT_win32
+       %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+       %idefine code_section section .text align=16 class=CODE use32
+       %idefine data_section section .data align=32 class=DATA use32
+       %idefine bss_section  section .bss  align=32 class=DATA use32
+%elifdef OBJ_FORMAT_aout
+       %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+       %idefine code_section section .text
+       %idefine data_section section .data
+       %idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_aoutb
+       %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+       %idefine code_section section .text
+       %idefine data_section section .data
+       %idefine bss_section  section .bss
+%elifdef OBJ_FORMAT_elf
+       %idefine code_section section .text align=16
+       %idefine data_section section .data align=32
+       %idefine bss_section  section .bss  align=32
+%else
+       %error unsupported object format!
+%endif
+
+%imacro cglobal 1
+       %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+               global _%1
+       %else
+               global %1
+       %endif
+%endmacro
+
+%imacro cextern 1
+       %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+               extern _%1
+       %else
+               extern %1
+       %endif
+%endmacro
+
+%imacro cident 1
+_%1:
+%1:
+%endmacro
diff --git a/src/libFLAC/ia32/stream_encoder_asm.nasm b/src/libFLAC/ia32/stream_encoder_asm.nasm
new file mode 100644 (file)
index 0000000..b7ecef8
--- /dev/null
@@ -0,0 +1,159 @@
+;  vim:filetype=nasm ts=8
+
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+       data_section
+
+cglobal precompute_partition_info_sums_32bit_asm_ia32_
+
+       code_section
+
+
+; **********************************************************************
+;
+; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+; void precompute_partition_info_sums_32bit_(
+;      const FLAC__int32 residual[],
+;      FLAC__uint64 abs_residual_partition_sums[],
+;      unsigned blocksize,
+;      unsigned predictor_order,
+;      unsigned min_partition_order,
+;      unsigned max_partition_order
+; )
+;
+       ALIGN 16
+cident precompute_partition_info_sums_32bit_asm_ia32_
+
+       ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
+       ;; [esp + 4]    const FLAC__int32 residual[]
+       ;; [esp + 8]    FLAC__uint64 abs_residual_partition_sums[]
+       ;; [esp + 12]   unsigned blocksize
+       ;; [esp + 16]   unsigned predictor_order
+       ;; [esp + 20]   unsigned min_partition_order
+       ;; [esp + 24]   unsigned max_partition_order
+       push    ebp
+       push    ebx
+       push    esi
+       push    edi
+       sub     esp, 8
+       ;; [esp + 28]   const FLAC__int32 residual[]
+       ;; [esp + 32]   FLAC__uint64 abs_residual_partition_sums[]
+       ;; [esp + 36]   unsigned blocksize
+       ;; [esp + 40]   unsigned predictor_order
+       ;; [esp + 44]   unsigned min_partition_order
+       ;; [esp + 48]   unsigned max_partition_order
+       ;; [esp]        partitions
+       ;; [esp + 4]    default_partition_samples
+
+       mov     ecx, [esp + 48]
+       mov     eax, 1
+       shl     eax, cl
+       mov     [esp], eax              ; [esp] <- partitions = 1u << max_partition_order;
+       mov     eax, [esp + 36]
+       shr     eax, cl
+       mov     [esp + 4], eax          ; [esp + 4] <- default_partition_samples = blocksize >> max_partition_order;
+
+       ;
+       ; first do max_partition_order
+       ;
+       mov     edi, [esp + 4]
+       sub     edi, [esp + 40]         ; edi <- end = (unsigned)(-(int)predictor_order) + default_partition_samples
+       xor     esi, esi                ; esi <- residual_sample = 0
+       xor     ecx, ecx                ; ecx <- partition = 0
+       mov     ebp, [esp + 28]         ; ebp <- residual[]
+       xor     ebx, ebx                ; ebx <- abs_residual_partition_sum = 0;
+       ; note we put the updates to 'end' and 'abs_residual_partition_sum' at the end of loop0 and in the initialization above so we could align loop0 and loop1
+       ALIGN   16
+.loop0:                                        ; for(partition = residual_sample = 0; partition < partitions; partition++) {
+.loop1:                                        ;   for( ; residual_sample < end; residual_sample++)
+       mov     eax, [ebp + esi * 4]
+       cdq
+       xor     eax, edx
+       sub     eax, edx
+       add     ebx, eax                ;     abs_residual_partition_sum += abs(residual[residual_sample]);
+       ;@@@@@@ check overflow flag and abort here?
+       add     esi, byte 1
+       cmp     esi, edi                ;   /* since the loop will always run at least once, we can put the loop check down here */
+       jb      .loop1
+.next1:
+       add     edi, [esp + 4]          ;   end += default_partition_samples;
+       mov     eax, [esp + 32]
+       mov     [eax + ecx * 8], ebx    ;   abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+       mov     [eax + ecx * 8 + 4], dword 0
+       xor     ebx, ebx                ;   abs_residual_partition_sum = 0;
+       add     ecx, byte 1
+       cmp     ecx, [esp]              ; /* since the loop will always run at least once, we can put the loop check down here */
+       jb      .loop0
+.next0:                                        ; }
+       ;
+       ; now merge partitions for lower orders
+       ;
+       mov     esi, [esp + 32]         ; esi <- abs_residual_partition_sums[from_partition==0];
+       mov     eax, [esp]
+       lea     edi, [esi + eax * 8]    ; edi <- abs_residual_partition_sums[to_partition==partitions];
+       mov     ecx, [esp + 48]
+       sub     ecx, byte 1             ; ecx <- partition_order = (int)max_partition_order - 1;
+       ALIGN 16
+.loop2:                                        ; for(; partition_order >= (int)min_partition_order; partition_order--) {
+       cmp     ecx, [esp + 44]
+       jl      .next2
+       mov     edx, 1
+       shl     edx, cl                 ;   const unsigned partitions = 1u << partition_order;
+       ALIGN 16
+.loop3:                                        ;   for(i = 0; i < partitions; i++) {
+       mov     eax, [esi]
+       mov     ebx, [esi + 4]
+       add     eax, [esi + 8]
+       adc     ebx, [esi + 12]
+       mov     [edi], eax
+       mov     [edi + 4], ebx          ;     a_r_p_s[to_partition] = a_r_p_s[from_partition] + a_r_p_s[from_partition+1];
+       add     esi, byte 16
+       add     edi, byte 8
+       sub     edx, byte 1
+       jnz     .loop3                  ;   }
+       sub     ecx, byte 1
+       jmp     .loop2                  ; }
+.next2:
+
+       add     esp, 8
+       pop     edi
+       pop     esi
+       pop     ebx
+       pop     ebp
+       ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+       section .note.GNU-stack noalloc
+%endif
diff --git a/src/libFLAC/include/Makefile.am b/src/libFLAC/include/Makefile.am
new file mode 100644 (file)
index 0000000..866a894
--- /dev/null
@@ -0,0 +1,31 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SUBDIRS = private protected
diff --git a/src/libFLAC/include/private/Makefile.am b/src/libFLAC/include/private/Makefile.am
new file mode 100644 (file)
index 0000000..e8abc58
--- /dev/null
@@ -0,0 +1,50 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+noinst_HEADERS = \
+       all.h \
+       bitmath.h \
+       bitreader.h \
+       bitwriter.h \
+       cpu.h \
+       crc.h \
+       fixed.h \
+       float.h \
+       format.h \
+       lpc.h \
+       md5.h \
+       memory.h \
+       metadata.h \
+       ogg_decoder_aspect.h \
+       ogg_encoder_aspect.h \
+       ogg_helper.h \
+       ogg_mapping.h \
+       stream_encoder_framing.h \
+       window.h
diff --git a/src/libFLAC/include/private/all.h b/src/libFLAC/include/private/all.h
new file mode 100644 (file)
index 0000000..304c471
--- /dev/null
@@ -0,0 +1,49 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__ALL_H
+#define FLAC__PRIVATE__ALL_H
+
+#include "bitmath.h"
+#include "bitreader.h"
+#include "bitwriter.h"
+#include "cpu.h"
+#include "crc.h"
+#include "fixed.h"
+#include "float.h"
+#include "format.h"
+#include "lpc.h"
+#include "md5.h"
+#include "memory.h"
+#include "metadata.h"
+#include "stream_encoder_framing.h"
+
+#endif
diff --git a/src/libFLAC/include/private/bitmath.h b/src/libFLAC/include/private/bitmath.h
new file mode 100644 (file)
index 0000000..87fa0fa
--- /dev/null
@@ -0,0 +1,42 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "FLAC/ordinals.h"
+
+unsigned FLAC__bitmath_ilog2(FLAC__uint32 v);
+unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v);
+unsigned FLAC__bitmath_silog2(int v);
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v);
+
+#endif
diff --git a/src/libFLAC/include/private/bitreader.h b/src/libFLAC/include/private/bitreader.h
new file mode 100644 (file)
index 0000000..fd0f6aa
--- /dev/null
@@ -0,0 +1,99 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITREADER_H
+#define FLAC__PRIVATE__BITREADER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+#include "cpu.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitReader;
+typedef struct FLAC__BitReader FLAC__BitReader;
+
+typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitReader *FLAC__bitreader_new(void);
+void FLAC__bitreader_delete(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd);
+void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+FLAC__bool FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+#    endif
+#  endif
+#endif
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen);
+
+FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
+#endif
diff --git a/src/libFLAC/include/private/bitwriter.h b/src/libFLAC/include/private/bitwriter.h
new file mode 100644 (file)
index 0000000..aa5c4f7
--- /dev/null
@@ -0,0 +1,103 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITWRITER_H
+#define FLAC__PRIVATE__BITWRITER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitWriter;
+typedef struct FLAC__BitWriter FLAC__BitWriter;
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitWriter *FLAC__bitwriter_new(void);
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw);
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw);
+void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw);
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out);
+
+/*
+ * CRC functions
+ *
+ * non-const *bw because they have to cal FLAC__bitwriter_get_buffer()
+ */
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc);
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw);
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */
+
+/*
+ * direct buffer access
+ *
+ * there may be no calls on the bitwriter between get and release.
+ * the bitwriter continues to own the returned buffer.
+ * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned()
+ */
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes);
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw);
+
+/*
+ * write functions
+ */
+FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/
+FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals);
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val);
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter);
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter);
+unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val);
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val);
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw);
+
+#endif
diff --git a/src/libFLAC/include/private/cpu.h b/src/libFLAC/include/private/cpu.h
new file mode 100644 (file)
index 0000000..651bb22
--- /dev/null
@@ -0,0 +1,88 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CPU_H
+#define FLAC__PRIVATE__CPU_H
+
+#include "FLAC/ordinals.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef enum {
+       FLAC__CPUINFO_TYPE_IA32,
+       FLAC__CPUINFO_TYPE_PPC,
+       FLAC__CPUINFO_TYPE_UNKNOWN
+} FLAC__CPUInfo_Type;
+
+typedef struct {
+       FLAC__bool cpuid;
+       FLAC__bool bswap;
+       FLAC__bool cmov;
+       FLAC__bool mmx;
+       FLAC__bool fxsr;
+       FLAC__bool sse;
+       FLAC__bool sse2;
+       FLAC__bool sse3;
+       FLAC__bool ssse3;
+       FLAC__bool _3dnow;
+       FLAC__bool ext3dnow;
+       FLAC__bool extmmx;
+} FLAC__CPUInfo_IA32;
+
+typedef struct {
+       FLAC__bool altivec;
+       FLAC__bool ppc64;
+} FLAC__CPUInfo_PPC;
+
+typedef struct {
+       FLAC__bool use_asm;
+       FLAC__CPUInfo_Type type;
+       union {
+               FLAC__CPUInfo_IA32 ia32;
+               FLAC__CPUInfo_PPC ppc;
+       } data;
+} FLAC__CPUInfo;
+
+void FLAC__cpu_info(FLAC__CPUInfo *info);
+
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
+void         FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx);
+FLAC__uint32 FLAC__cpu_info_extended_amd_asm_ia32(void);
+#endif
+#endif
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/crc.h b/src/libFLAC/include/private/crc.h
new file mode 100644 (file)
index 0000000..0b67fb4
--- /dev/null
@@ -0,0 +1,61 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + x^0
+** init = 0
+*/
+extern FLAC__byte const FLAC__crc8_table[256];
+#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)];
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc);
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc);
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern unsigned FLAC__crc16_table[256];
+
+#define FLAC__CRC16_UPDATE(data, crc) (((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]))
+/* this alternate may be faster on some systems/compilers */
+#if 0
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len);
+
+#endif
diff --git a/src/libFLAC/include/private/fixed.h b/src/libFLAC/include/private/fixed.h
new file mode 100644 (file)
index 0000000..6656b79
--- /dev/null
@@ -0,0 +1,97 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+/*
+ *     FLAC__fixed_compute_best_predictor()
+ *     --------------------------------------------------------------------
+ *     Compute the best fixed predictor and the expected bits-per-sample
+ *  of the residual signal for each order.  The _wide() version uses
+ *  64-bit integers which is statistically necessary when bits-per-
+ *  sample + log2(blocksize) > 30
+ *
+ *     IN data[0,data_len-1]
+ *     IN data_len
+ *     OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#   ifdef FLAC__HAS_NASM
+unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#   endif
+#  endif
+# endif
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+
+/*
+ *     FLAC__fixed_compute_residual()
+ *     --------------------------------------------------------------------
+ *     Compute the residual signal obtained from sutracting the predicted
+ *     signal from the original.
+ *
+ *     IN data[-order,data_len-1]        original signal (NOTE THE INDICES!)
+ *     IN data_len                       length of original signal
+ *     IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *     OUT residual[0,data_len-1]        residual signal
+ */
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]);
+
+/*
+ *     FLAC__fixed_restore_signal()
+ *     --------------------------------------------------------------------
+ *     Restore the original signal by summing the residual and the
+ *     predictor.
+ *
+ *     IN residual[0,data_len-1]         residual signal
+ *     IN data_len                       length of original signal
+ *     IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *     *** IMPORTANT: the caller must pass in the historical samples:
+ *     IN  data[-order,-1]               previously-reconstructed historical samples
+ *     OUT data[0,data_len-1]            original signal
+ */
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]);
+
+#endif
diff --git a/src/libFLAC/include/private/float.h b/src/libFLAC/include/private/float.h
new file mode 100644 (file)
index 0000000..73313f6
--- /dev/null
@@ -0,0 +1,97 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FLOAT_H
+#define FLAC__PRIVATE__FLOAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "FLAC/ordinals.h"
+
+/*
+ * These typedefs make it easier to ensure that integer versions of
+ * the library really only contain integer operations.  All the code
+ * in libFLAC should use FLAC__float and FLAC__double in place of
+ * float and double, and be protected by checks of the macro
+ * FLAC__INTEGER_ONLY_LIBRARY.
+ *
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+typedef double FLAC__double;
+typedef float FLAC__float;
+/*
+ * WATCHOUT: changing FLAC__real will change the signatures of many
+ * functions that have assembly language equivalents and break them.
+ */
+typedef float FLAC__real;
+#else
+/*
+ * The convention for FLAC__fixedpoint is to use the upper 16 bits
+ * for the integer part and lower 16 bits for the fractional part.
+ */
+typedef FLAC__int32 FLAC__fixedpoint;
+extern const FLAC__fixedpoint FLAC__FP_ZERO;
+extern const FLAC__fixedpoint FLAC__FP_ONE_HALF;
+extern const FLAC__fixedpoint FLAC__FP_ONE;
+extern const FLAC__fixedpoint FLAC__FP_LN2;
+extern const FLAC__fixedpoint FLAC__FP_E;
+
+#define FLAC__fixedpoint_trunc(x) ((x)>>16)
+
+#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) )
+
+#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) )
+
+/*
+ *     FLAC__fixedpoint_log2()
+ *     --------------------------------------------------------------------
+ *     Returns the base-2 logarithm of the fixed-point number 'x' using an
+ *     algorithm by Knuth for x >= 1.0
+ *
+ *     'fracbits' is the number of fractional bits of 'x'.  'fracbits' must
+ *     be < 32 and evenly divisible by 4 (0 is OK but not very precise).
+ *
+ *     'precision' roughly limits the number of iterations that are done;
+ *     use (unsigned)(-1) for maximum precision.
+ *
+ *     If 'x' is less than one -- that is, x < (1<<fracbits) -- then this
+ *     function will punt and return 0.
+ *
+ *     The return value will also have 'fracbits' fractional bits.
+ */
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision);
+
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/format.h b/src/libFLAC/include/private/format.h
new file mode 100644 (file)
index 0000000..7f5cc93
--- /dev/null
@@ -0,0 +1,44 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "FLAC/format.h"
+
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order);
+
+#endif
diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h
new file mode 100644 (file)
index 0000000..2cb139b
--- /dev/null
@@ -0,0 +1,214 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *     FLAC__lpc_window_data()
+ *     --------------------------------------------------------------------
+ *     Applies the given window to the data.
+ *  OPT: asm implementation
+ *
+ *     IN in[0,data_len-1]
+ *     IN window[0,data_len-1]
+ *     OUT out[0,lag-1]
+ *     IN data_len
+ */
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len);
+
+/*
+ *     FLAC__lpc_compute_autocorrelation()
+ *     --------------------------------------------------------------------
+ *     Compute the autocorrelation for lags between 0 and lag-1.
+ *     Assumes data[] outside of [0,data_len-1] == 0.
+ *     Asserts that lag > 0.
+ *
+ *     IN data[0,data_len-1]
+ *     IN data_len
+ *     IN 0 < lag <= data_len
+ *     OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#endif
+
+/*
+ *     FLAC__lpc_compute_lp_coefficients()
+ *     --------------------------------------------------------------------
+ *     Computes LP coefficients for orders 1..max_order.
+ *     Do not call if autoc[0] == 0.0.  This means the signal is zero
+ *     and there is no point in calculating a predictor.
+ *
+ *     IN autoc[0,max_order]                      autocorrelation values
+ *     IN 0 < max_order <= FLAC__MAX_LPC_ORDER    max LP order to compute
+ *     OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ *     *** IMPORTANT:
+ *     *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ *     OUT error[0,max_order-1]                   error for each order (more
+ *                                                specifically, the variance of
+ *                                                the error signal times # of
+ *                                                samples in the signal)
+ *
+ *     Example: if max_order is 9, the LP coefficients for order 9 will be
+ *              in lp_coeff[8][0,8], the LP coefficients for order 8 will be
+ *                      in lp_coeff[7][0,7], etc.
+ */
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]);
+
+/*
+ *     FLAC__lpc_quantize_coefficients()
+ *     --------------------------------------------------------------------
+ *     Quantizes the LP coefficients.  NOTE: precision + bits_per_sample
+ *     must be less than 32 (sizeof(FLAC__int32)*8).
+ *
+ *     IN lp_coeff[0,order-1]    LP coefficients
+ *     IN order                  LP order
+ *     IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ *                               desired precision (in bits, including sign
+ *                               bit) of largest coefficient
+ *     OUT qlp_coeff[0,order-1]  quantized coefficients
+ *     OUT shift                 # of bits to shift right to get approximated
+ *                               LP coefficients.  NOTE: could be negative.
+ *     RETURN 0 => quantization OK
+ *            1 => coefficients require too much shifting for *shift to
+ *              fit in the LPC subframe header.  'shift' is unset.
+ *         2 => coefficients are all zero, which is bad.  'shift' is
+ *              unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ *     FLAC__lpc_compute_residual_from_qlp_coefficients()
+ *     --------------------------------------------------------------------
+ *     Compute the residual signal obtained from sutracting the predicted
+ *     signal from the original.
+ *
+ *     IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ *     IN data_len                length of original signal
+ *     IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *     IN order > 0               LP order
+ *     IN lp_quantization         quantization of LP coefficients in bits
+ *     OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+/*
+ *     FLAC__lpc_restore_signal()
+ *     --------------------------------------------------------------------
+ *     Restore the original signal by summing the residual and the
+ *     predictor.
+ *
+ *     IN residual[0,data_len-1]  residual signal
+ *     IN data_len                length of original signal
+ *     IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *     IN order > 0               LP order
+ *     IN lp_quantization         quantization of LP coefficients in bits
+ *     *** IMPORTANT: the caller must pass in the historical samples:
+ *     IN  data[-order,-1]        previously-reconstructed historical samples
+ *     OUT data[0,data_len-1]     original signal
+ */
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#    endif /* FLAC__HAS_NASM */
+#  elif defined FLAC__CPU_PPC
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#  endif/* FLAC__CPU_IA32 || FLAC__CPU_PPC */
+#endif /* FLAC__NO_ASM */
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *     FLAC__lpc_compute_expected_bits_per_residual_sample()
+ *     --------------------------------------------------------------------
+ *     Compute the expected number of bits per residual signal sample
+ *     based on the LP error (which is related to the residual variance).
+ *
+ *     IN lpc_error >= 0.0   error returned from calculating LP coefficients
+ *     IN total_samples > 0  # of samples in residual signal
+ *     RETURN                expected bits per sample
+ */
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples);
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale);
+
+/*
+ *     FLAC__lpc_compute_best_order()
+ *     --------------------------------------------------------------------
+ *     Compute the best order from the array of signal errors returned
+ *     during coefficient computation.
+ *
+ *     IN lpc_error[0,max_order-1] >= 0.0  error returned from calculating LP coefficients
+ *     IN max_order > 0                    max LP order
+ *     IN total_samples > 0                # of samples in residual signal
+ *     IN overhead_bits_per_order          # of bits overhead for each increased LP order
+ *                                         (includes warmup sample size and quantized LP coefficient)
+ *     RETURN [1,max_order]                best order
+ */
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/libFLAC/include/private/md5.h b/src/libFLAC/include/private/md5.h
new file mode 100644 (file)
index 0000000..e5f675a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain, with no warranty.
+ */
+
+#include "FLAC/ordinals.h"
+
+typedef struct {
+       FLAC__uint32 in[16];
+       FLAC__uint32 buf[4];
+       FLAC__uint32 bytes[2];
+       FLAC__byte *internal_buf;
+       size_t capacity;
+} FLAC__MD5Context;
+
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
+
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+
+#endif
diff --git a/src/libFLAC/include/private/memory.h b/src/libFLAC/include/private/memory.h
new file mode 100644 (file)
index 0000000..7852c81
--- /dev/null
@@ -0,0 +1,56 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__MEMORY_H
+#define FLAC__PRIVATE__MEMORY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h> /* for size_t */
+
+#include "private/float.h"
+#include "FLAC/ordinals.h" /* for FLAC__bool */
+
+/* Returns the unaligned address returned by malloc.
+ * Use free() on this address to deallocate.
+ */
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/metadata.h b/src/libFLAC/include/private/metadata.h
new file mode 100644 (file)
index 0000000..b5268c9
--- /dev/null
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "FLAC/metadata.h"
+
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
diff --git a/src/libFLAC/include/private/ogg_decoder_aspect.h b/src/libFLAC/include/private/ogg_decoder_aspect.h
new file mode 100644 (file)
index 0000000..df2b6b5
--- /dev/null
@@ -0,0 +1,79 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_DECODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */
+
+typedef struct FLAC__OggDecoderAspect {
+       /* these are storage for values that can be set through the API */
+       FLAC__bool use_first_serial_number;
+       long serial_number;
+
+       /* these are for internal state related to Ogg decoding */
+       ogg_stream_state stream_state;
+       ogg_sync_state sync_state;
+       unsigned version_major, version_minor;
+       FLAC__bool need_serial_number;
+       FLAC__bool end_of_stream;
+       FLAC__bool have_working_page; /* only if true will the following vars be valid */
+       ogg_page working_page;
+       FLAC__bool have_working_packet; /* only if true will the following vars be valid */
+       ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */
+} FLAC__OggDecoderAspect;
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value);
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect);
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect);
+
+typedef enum {
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR,
+       FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR
+} FLAC__OggDecoderAspectReadStatus;
+
+typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data);
+
+#endif
diff --git a/src/libFLAC/include/private/ogg_encoder_aspect.h b/src/libFLAC/include/private/ogg_encoder_aspect.h
new file mode 100644 (file)
index 0000000..290da07
--- /dev/null
@@ -0,0 +1,62 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_ENCODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */
+
+typedef struct FLAC__OggEncoderAspect {
+       /* these are storage for values that can be set through the API */
+       long serial_number;
+       unsigned num_metadata;
+
+       /* these are for internal state related to Ogg encoding */
+       ogg_stream_state stream_state;
+       ogg_page page;
+       FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */
+       FLAC__bool is_first_packet;
+       FLAC__uint64 samples_written;
+} FLAC__OggEncoderAspect;
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value);
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value);
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect);
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect);
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect);
+
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data);
+#endif
diff --git a/src/libFLAC/include/private/ogg_helper.h b/src/libFLAC/include/private/ogg_helper.h
new file mode 100644 (file)
index 0000000..389be18
--- /dev/null
@@ -0,0 +1,43 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_HELPER_H
+#define FLAC__PRIVATE__OGG_HELPER_H
+
+#include <ogg/ogg.h>
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */
+
+void simple_ogg_page__init(ogg_page *page);
+void simple_ogg_page__clear(ogg_page *page);
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data);
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data);
+
+#endif
diff --git a/src/libFLAC/include/private/ogg_mapping.h b/src/libFLAC/include/private/ogg_mapping.h
new file mode 100644 (file)
index 0000000..07dd8b2
--- /dev/null
@@ -0,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_MAPPING_H
+#define FLAC__PRIVATE__OGG_MAPPING_H
+
+#include "FLAC/ordinals.h"
+
+/** The length of the 'FLAC' magic in bytes. */
+#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */
+
+extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */
+
+/** The length of the 'FLAC' magic in bytes. */
+#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u)
+
+extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */
+
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */
+
+/** The length of the Ogg FLAC mapping major version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u)
+
+/** The length of the Ogg FLAC mapping minor version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */
+
+/** The length of the #-of-header-packets number bytes. */
+#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u)
+
+#endif
diff --git a/src/libFLAC/include/private/stream_encoder_framing.h b/src/libFLAC/include/private/stream_encoder_framing.h
new file mode 100644 (file)
index 0000000..4865c16
--- /dev/null
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+
+#include "FLAC/format.h"
+#include "bitwriter.h"
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw);
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+
+#endif
diff --git a/src/libFLAC/include/private/window.h b/src/libFLAC/include/private/window.h
new file mode 100644 (file)
index 0000000..01e0fc4
--- /dev/null
@@ -0,0 +1,71 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *     FLAC__window_*()
+ *     --------------------------------------------------------------------
+ *     Calculates window coefficients according to different apodization
+ *     functions.
+ *
+ *     OUT window[0,L-1]
+ *     IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/libFLAC/include/protected/Makefile.am b/src/libFLAC/include/protected/Makefile.am
new file mode 100644 (file)
index 0000000..66c697c
--- /dev/null
@@ -0,0 +1,34 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+noinst_HEADERS = \
+       all.h \
+       stream_decoder.h \
+       stream_encoder.h
diff --git a/src/libFLAC/include/protected/all.h b/src/libFLAC/include/protected/all.h
new file mode 100644 (file)
index 0000000..2921092
--- /dev/null
@@ -0,0 +1,38 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__ALL_H
+#define FLAC__PROTECTED__ALL_H
+
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+#endif
diff --git a/src/libFLAC/include/protected/stream_decoder.h b/src/libFLAC/include/protected/stream_decoder.h
new file mode 100644 (file)
index 0000000..9108ca7
--- /dev/null
@@ -0,0 +1,58 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "FLAC/stream_decoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_decoder_aspect.h"
+#endif
+
+typedef struct FLAC__StreamDecoderProtected {
+       FLAC__StreamDecoderState state;
+       unsigned channels;
+       FLAC__ChannelAssignment channel_assignment;
+       unsigned bits_per_sample;
+       unsigned sample_rate; /* in Hz */
+       unsigned blocksize; /* in samples (per channel) */
+       FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+#if FLAC__HAS_OGG
+       FLAC__OggDecoderAspect ogg_decoder_aspect;
+#endif
+} FLAC__StreamDecoderProtected;
+
+/*
+ * return the number of input bytes consumed
+ */
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+#endif
diff --git a/src/libFLAC/include/protected/stream_encoder.h b/src/libFLAC/include/protected/stream_encoder.h
new file mode 100644 (file)
index 0000000..4101ee5
--- /dev/null
@@ -0,0 +1,110 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_ENCODER_H
+#define FLAC__PROTECTED__STREAM_ENCODER_H
+
+#include "FLAC/stream_encoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_encoder_aspect.h"
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#include "private/float.h"
+
+#define FLAC__MAX_APODIZATION_FUNCTIONS 32
+
+typedef enum {
+       FLAC__APODIZATION_BARTLETT,
+       FLAC__APODIZATION_BARTLETT_HANN,
+       FLAC__APODIZATION_BLACKMAN,
+       FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE,
+       FLAC__APODIZATION_CONNES,
+       FLAC__APODIZATION_FLATTOP,
+       FLAC__APODIZATION_GAUSS,
+       FLAC__APODIZATION_HAMMING,
+       FLAC__APODIZATION_HANN,
+       FLAC__APODIZATION_KAISER_BESSEL,
+       FLAC__APODIZATION_NUTTALL,
+       FLAC__APODIZATION_RECTANGLE,
+       FLAC__APODIZATION_TRIANGLE,
+       FLAC__APODIZATION_TUKEY,
+       FLAC__APODIZATION_WELCH
+} FLAC__ApodizationFunction;
+
+typedef struct {
+       FLAC__ApodizationFunction type;
+       union {
+               struct {
+                       FLAC__real stddev;
+               } gauss;
+               struct {
+                       FLAC__real p;
+               } tukey;
+       } parameters;
+} FLAC__ApodizationSpecification;
+
+#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+typedef struct FLAC__StreamEncoderProtected {
+       FLAC__StreamEncoderState state;
+       FLAC__bool verify;
+       FLAC__bool streamable_subset;
+       FLAC__bool do_md5;
+       FLAC__bool do_mid_side_stereo;
+       FLAC__bool loose_mid_side_stereo;
+       unsigned channels;
+       unsigned bits_per_sample;
+       unsigned sample_rate;
+       unsigned blocksize;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       unsigned num_apodizations;
+       FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
+#endif
+       unsigned max_lpc_order;
+       unsigned qlp_coeff_precision;
+       FLAC__bool do_qlp_coeff_prec_search;
+       FLAC__bool do_exhaustive_model_search;
+       FLAC__bool do_escape_coding;
+       unsigned min_residual_partition_order;
+       unsigned max_residual_partition_order;
+       unsigned rice_parameter_search_dist;
+       FLAC__uint64 total_samples_estimate;
+       FLAC__StreamMetadata **metadata;
+       unsigned num_metadata_blocks;
+       FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
+#if FLAC__HAS_OGG
+       FLAC__OggEncoderAspect ogg_encoder_aspect;
+#endif
+} FLAC__StreamEncoderProtected;
+
+#endif
diff --git a/src/libFLAC/libFLAC.m4 b/src/libFLAC/libFLAC.m4
new file mode 100644 (file)
index 0000000..24eb0c5
--- /dev/null
@@ -0,0 +1,114 @@
+# Configure paths for libFLAC
+# "Inspired" by ogg.m4
+
+dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libFLAC, and define LIBFLAC_CFLAGS, LIBFLAC_LIBS, LIBFLAC_LIBDIR
+dnl
+AC_DEFUN([AM_PATH_LIBFLAC],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libFLAC,[  --with-libFLAC=PFX   Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="")
+AC_ARG_WITH(libFLAC-libraries,[  --with-libFLAC-libraries=DIR   Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="")
+AC_ARG_WITH(libFLAC-includes,[  --with-libFLAC-includes=DIR   Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="")
+AC_ARG_ENABLE(libFLACtest, [  --disable-libFLACtest       Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes)
+
+  if test "x$libFLAC_libraries" != "x" ; then
+    LIBFLAC_LIBDIR="$libFLAC_libraries"
+  elif test "x$libFLAC_prefix" != "x" ; then
+    LIBFLAC_LIBDIR="$libFLAC_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    LIBFLAC_LIBDIR="$libdir"
+  fi
+
+  LIBFLAC_LIBS="-L$LIBFLAC_LIBDIR -lFLAC $OGG_LIBS -lm"
+
+  if test "x$libFLAC_includes" != "x" ; then
+    LIBFLAC_CFLAGS="-I$libFLAC_includes"
+  elif test "x$libFLAC_prefix" != "x" ; then
+    LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
+  elif test "$prefix" != "xNONE"; then
+    LIBFLAC_CFLAGS=""
+  fi
+
+  AC_MSG_CHECKING(for libFLAC)
+  no_libFLAC=""
+
+
+  if test "x$enable_libFLACtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+    ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+    CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+    CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+    LIBS="$LIBS $LIBFLAC_LIBS"
+    LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+dnl
+dnl Now check if the installed libFLAC is sufficiently new.
+dnl
+      rm -f conf.libFLACtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC/format.h>
+
+int main ()
+{
+  system("touch conf.libFLACtest");
+  return 0;
+}
+
+],, no_libFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+  fi
+
+  if test "x$no_libFLAC" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.libFLACtest ; then
+       :
+     else
+       echo "*** Could not run libFLAC test program, checking why..."
+       CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+       CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+       LIBS="$LIBS $LIBFLAC_LIBS"
+       LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <FLAC/format.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding libFLAC or finding the wrong"
+       echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means libFLAC was incorrectly installed"
+       echo "*** or that you have moved libFLAC since it was installed. In the latter case, you"
+       echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ])
+       CFLAGS="$ac_save_CFLAGS"
+       CXXFLAGS="$ac_save_CXXFLAGS"
+       LIBS="$ac_save_LIBS"
+       LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+     fi
+     LIBFLAC_CFLAGS=""
+     LIBFLAC_LIBDIR=""
+     LIBFLAC_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(LIBFLAC_CFLAGS)
+  AC_SUBST(LIBFLAC_LIBDIR)
+  AC_SUBST(LIBFLAC_LIBS)
+  rm -f conf.libFLACtest
+])
diff --git a/src/libFLAC/libFLAC_dynamic.dsp b/src/libFLAC/libFLAC_dynamic.dsp
new file mode 100644 (file)
index 0000000..243f639
--- /dev/null
@@ -0,0 +1,464 @@
+# Microsoft Developer Studio Project File - Name="libFLAC_dynamic" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=libFLAC_dynamic - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC_dynamic.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC_dynamic.mak" CFG="libFLAC_dynamic - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libFLAC_dynamic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "libFLAC_dynamic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "libFLAC"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_dynamic"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I ".\include" /I "..\..\include" /D "NDEBUG" /D "FLAC_API_EXPORTS" /D "FLAC__HAS_OGG" /D VERSION=\"1.2.1\" /D "FLAC__CPU_IA32" /D "FLAC__HAS_NASM" /D "FLAC__USE_3DNOW" /D "_WINDOWS" /D "_WINDLL" /D "WIN32" /D "_USRDLL" /FR /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG" /d "_USRDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\obj\release\bin/libFLAC.dll"\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_dynamic"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I ".\include" /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__OVERFLOW_DETECT" /D "FLAC_API_EXPORTS" /D "FLAC__HAS_OGG" /D VERSION=\"1.2.1\" /D "FLAC__CPU_IA32" /D "FLAC__HAS_NASM" /D "FLAC__USE_3DNOW" /D "_WINDOWS" /D "_WINDLL" /D "WIN32" /D "_USRDLL" /FR /FD /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG" /d "_USRDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\..\obj\debug\bin/libFLAC.dll" /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libFLAC_dynamic - Win32 Release"\r
+# Name "libFLAC_dynamic - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Group "Assembly Files (ia32)"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\bitreader_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/bitreader_asm.nasm"       \r
+# Begin Custom Build\r
+InputPath=.\ia32\bitreader_asm.nasm\r
+\r
+"ia32/bitreader_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/bitreader_asm.nasm"       \r
+# Begin Custom Build\r
+InputPath=.\ia32\bitreader_asm.nasm\r
+\r
+"ia32/bitreader_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\cpu_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/cpu_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\cpu_asm.nasm\r
+\r
+"ia32/cpu_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/cpu_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\cpu_asm.nasm\r
+\r
+"ia32/cpu_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\fixed_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+USERDEP__FIXED="ia32/fixed_asm.nasm"   \r
+# Begin Custom Build\r
+InputPath=.\ia32\fixed_asm.nasm\r
+\r
+"ia32/fixed_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+USERDEP__FIXED="ia32/fixed_asm.nasm"   \r
+# Begin Custom Build\r
+InputPath=.\ia32\fixed_asm.nasm\r
+\r
+"ia32/fixed_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\lpc_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+USERDEP__LPC_A="ia32/lpc_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\lpc_asm.nasm\r
+\r
+"ia32/lpc_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+USERDEP__LPC_A="ia32/lpc_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\lpc_asm.nasm\r
+\r
+"ia32/lpc_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\stream_encoder_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_dynamic - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/stream_encoder_asm.nasm"  \r
+# Begin Custom Build\r
+InputPath=.\ia32\stream_encoder_asm.nasm\r
+\r
+"ia32/stream_encoder_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_dynamic - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/stream_encoder_asm.nasm"  \r
+# Begin Custom Build\r
+InputPath=.\ia32\stream_encoder_asm.nasm\r
+\r
+"ia32/stream_encoder_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\nasm.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\bitmath.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\bitreader.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\bitwriter.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\cpu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\crc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\fixed.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\float.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\format.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\lpc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\md5.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\memory.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_iterators.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_object.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_decoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_encoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_helper.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_mapping.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder_framing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\window.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitmath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitreader.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitwriter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\cpu.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\crc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\fixed.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\float.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\format.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\lpc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\md5.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\memory.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\metadata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_decoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_encoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_helper.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_mapping.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\stream_encoder_framing.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\window.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\stream_encoder.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\assert.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\export.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\format.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\metadata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\ordinals.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\stream_encoder.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/libFLAC/libFLAC_dynamic.vcproj b/src/libFLAC/libFLAC_dynamic.vcproj
new file mode 100644 (file)
index 0000000..fe2a20c
--- /dev/null
@@ -0,0 +1,540 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="libFLAC_dynamic"\r
+       ProjectGUID="{4cefbc83-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="libFLAC_dynamic"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__USE_3DNOW;VERSION=\&quot;1.2.0\&quot;;DEBUG;FLAC__OVERFLOW_DETECT"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLAC_API_EXPORTS;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__USE_3DNOW;VERSION=\&quot;1.2.0\&quot;"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\include\private\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\protected\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitmath.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitreader.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitwriter.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\cpu.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\crc.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\fixed.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\float.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\format.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\lpc.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\md5.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\memory.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\metadata.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ia32\nasm.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_decoder_aspect.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_encoder_aspect.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_helper.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_mapping.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\protected\stream_decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\protected\stream_encoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\stream_encoder_framing.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\window.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\bitmath.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\bitreader.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\bitwriter.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\cpu.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\crc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\fixed.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\float.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\format.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\lpc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\memory.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_iterators.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_object.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_decoder_aspect.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_encoder_aspect.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_helper.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_mapping.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_decoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder_framing.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\window.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\assert.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\callback.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\export.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\format.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\metadata.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\ordinals.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\stream_decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\stream_encoder.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\ia32\bitreader_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/bitreader_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/bitreader_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/bitreader_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/bitreader_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\release_static\BuildLog.htm"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\cpu_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/cpu_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/cpu_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\fixed_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/fixed_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/fixed_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\lpc_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/lpc_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/lpc_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\stream_encoder_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/stream_encoder_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/stream_encoder_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/stream_encoder_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/stream_encoder_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/libFLAC/libFLAC_static.dsp b/src/libFLAC/libFLAC_static.dsp
new file mode 100644 (file)
index 0000000..9726b8a
--- /dev/null
@@ -0,0 +1,457 @@
+# Microsoft Developer Studio Project File - Name="libFLAC_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=libFLAC_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libFLAC_static.mak" CFG="libFLAC_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libFLAC_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "libFLAC_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "libFLAC"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /Op /I ".\include" /I "..\..\include" /D VERSION=\"1.2.1\" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "FLAC__CPU_IA32" /D "FLAC__HAS_NASM" /D "FLAC__USE_3DNOW" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\include" /D VERSION=\"1.2.1\" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "FLAC__CPU_IA32" /D "FLAC__HAS_NASM" /D "FLAC__USE_3DNOW" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "FLAC__OVERFLOW_DETECT" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libFLAC_static - Win32 Release"\r
+# Name "libFLAC_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Group "Assembly Files (ia32)"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\bitreader_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/bitreader_asm.nasm"       \r
+# Begin Custom Build\r
+InputPath=.\ia32\bitreader_asm.nasm\r
+\r
+"ia32/bitreader_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/bitreader_asm.nasm"       \r
+# Begin Custom Build\r
+InputPath=.\ia32\bitreader_asm.nasm\r
+\r
+"ia32/bitreader_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\cpu_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/cpu_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\cpu_asm.nasm\r
+\r
+"ia32/cpu_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/cpu_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\cpu_asm.nasm\r
+\r
+"ia32/cpu_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\fixed_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+USERDEP__FIXED="ia32/fixed_asm.nasm"   \r
+# Begin Custom Build\r
+InputPath=.\ia32\fixed_asm.nasm\r
+\r
+"ia32/fixed_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+USERDEP__FIXED="ia32/fixed_asm.nasm"   \r
+# Begin Custom Build\r
+InputPath=.\ia32\fixed_asm.nasm\r
+\r
+"ia32/fixed_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\lpc_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+USERDEP__LPC_A="ia32/lpc_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\lpc_asm.nasm\r
+\r
+"ia32/lpc_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+USERDEP__LPC_A="ia32/lpc_asm.nasm"     \r
+# Begin Custom Build\r
+InputPath=.\ia32\lpc_asm.nasm\r
+\r
+"ia32/lpc_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\stream_encoder_asm.nasm\r
+\r
+!IF  "$(CFG)" == "libFLAC_static - Win32 Release"\r
+\r
+USERDEP__CPU_A="ia32/stream_encoder_asm.nasm"  \r
+# Begin Custom Build\r
+InputPath=.\ia32\stream_encoder_asm.nasm\r
+\r
+"ia32/stream_encoder_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "libFLAC_static - Win32 Debug"\r
+\r
+USERDEP__CPU_A="ia32/stream_encoder_asm.nasm"  \r
+# Begin Custom Build\r
+InputPath=.\ia32\stream_encoder_asm.nasm\r
+\r
+"ia32/stream_encoder_asm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ia32\nasm.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\bitmath.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\bitreader.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\bitwriter.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\cpu.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\crc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\fixed.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\float.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\format.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\lpc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\md5.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\memory.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_iterators.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_object.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_decoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_encoder_aspect.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_helper.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ogg_mapping.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_decoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\stream_encoder_framing.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\window.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitmath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitreader.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\bitwriter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\cpu.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\crc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\fixed.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\float.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\format.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\lpc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\md5.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\memory.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\metadata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_decoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_encoder_aspect.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_helper.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\ogg_mapping.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\stream_encoder_framing.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\window.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\protected\stream_encoder.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\assert.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\export.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\format.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\metadata.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\ordinals.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\stream_decoder.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\FLAC\stream_encoder.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/libFLAC/libFLAC_static.vcproj b/src/libFLAC/libFLAC_static.vcproj
new file mode 100644 (file)
index 0000000..fdb1b2f
--- /dev/null
@@ -0,0 +1,505 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="libFLAC_static"\r
+       ProjectGUID="{4cefbc84-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="libFLAC_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__USE_3DNOW;VERSION=\&quot;1.2.0\&quot;;FLAC__NO_DLL;DEBUG;FLAC__OVERFLOW_DETECT"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__HAS_OGG;FLAC__CPU_IA32;FLAC__HAS_NASM;FLAC__USE_3DNOW;VERSION=\&quot;1.2.0\&quot;;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\include\protected\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitmath.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitreader.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\bitwriter.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\cpu.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\crc.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\fixed.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\float.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\format.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\lpc.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\md5.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\memory.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\metadata.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ia32\nasm.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_decoder_aspect.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_encoder_aspect.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_helper.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\ogg_mapping.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\protected\stream_decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\protected\stream_encoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\stream_encoder_framing.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\private\window.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\assert.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\callback.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\export.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\format.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\metadata.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\ordinals.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\stream_decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\include\FLAC\stream_encoder.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\bitmath.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\bitreader.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\bitwriter.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\cpu.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\crc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\fixed.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\float.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\format.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\lpc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\md5.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\memory.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_iterators.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_object.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_decoder_aspect.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_encoder_aspect.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_helper.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ogg_mapping.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_decoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\stream_encoder_framing.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\window.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\ia32\bitreader_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/bitreader_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/bitreader_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/bitreader_asm.nasm -o ia32/bitreader_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/bitreader_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/bitreader_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\cpu_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/cpu_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/cpu_asm.nasm -o ia32/cpu_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/cpu_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/cpu_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\fixed_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/fixed_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/fixed_asm.nasm -o ia32/fixed_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/fixed_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/fixed_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\lpc_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/lpc_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/lpc_asm.nasm -o ia32/lpc_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/lpc_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/lpc_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath=".\ia32\stream_encoder_asm.nasm"\r
+                       >\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/stream_encoder_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/stream_encoder_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Release|Win32"\r
+                               >\r
+                               <Tool\r
+                                       Name="VCCustomBuildTool"\r
+                                       CommandLine="nasmw.exe -f win32 -d OBJ_FORMAT_win32 -i ia32/ ia32/stream_encoder_asm.nasm -o ia32/stream_encoder_asm.obj&#x0D;&#x0A;"\r
+                                       AdditionalDependencies="ia32/stream_encoder_asm.nasm;ia32/nasm.h"\r
+                                       Outputs="ia32/stream_encoder_asm.obj"\r
+                               />\r
+                       </FileConfiguration>\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/libFLAC/lpc.c b/src/libFLAC/lpc.c
new file mode 100644 (file)
index 0000000..7806348
--- /dev/null
@@ -0,0 +1,1377 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
+#include <stdio.h>
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len)
+{
+       unsigned i;
+       for(i = 0; i < data_len; i++)
+               out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+{
+       /* a readable, but slower, version */
+#if 0
+       FLAC__real d;
+       unsigned i;
+
+       FLAC__ASSERT(lag > 0);
+       FLAC__ASSERT(lag <= data_len);
+
+       /*
+        * Technically we should subtract the mean first like so:
+        *   for(i = 0; i < data_len; i++)
+        *     data[i] -= mean;
+        * but it appears not to make enough of a difference to matter, and
+        * most signals are already closely centered around zero
+        */
+       while(lag--) {
+               for(i = lag, d = 0.0; i < data_len; i++)
+                       d += data[i] * data[i - lag];
+               autoc[lag] = d;
+       }
+#endif
+
+       /*
+        * this version tends to run faster because of better data locality
+        * ('data_len' is usually much larger than 'lag')
+        */
+       FLAC__real d;
+       unsigned sample, coeff;
+       const unsigned limit = data_len - lag;
+
+       FLAC__ASSERT(lag > 0);
+       FLAC__ASSERT(lag <= data_len);
+
+       for(coeff = 0; coeff < lag; coeff++)
+               autoc[coeff] = 0.0;
+       for(sample = 0; sample <= limit; sample++) {
+               d = data[sample];
+               for(coeff = 0; coeff < lag; coeff++)
+                       autoc[coeff] += d * data[sample+coeff];
+       }
+       for(; sample < data_len; sample++) {
+               d = data[sample];
+               for(coeff = 0; coeff < data_len - sample; coeff++)
+                       autoc[coeff] += d * data[sample+coeff];
+       }
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[])
+{
+       unsigned i, j;
+       FLAC__double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
+
+       FLAC__ASSERT(0 != max_order);
+       FLAC__ASSERT(0 < *max_order);
+       FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER);
+       FLAC__ASSERT(autoc[0] != 0.0);
+
+       err = autoc[0];
+
+       for(i = 0; i < *max_order; i++) {
+               /* Sum up this iteration's reflection coefficient. */
+               r = -autoc[i+1];
+               for(j = 0; j < i; j++)
+                       r -= lpc[j] * autoc[i-j];
+               ref[i] = (r/=err);
+
+               /* Update LPC coefficients and total error. */
+               lpc[i]=r;
+               for(j = 0; j < (i>>1); j++) {
+                       FLAC__double tmp = lpc[j];
+                       lpc[j] += r * lpc[i-1-j];
+                       lpc[i-1-j] += r * tmp;
+               }
+               if(i & 1)
+                       lpc[j] += lpc[j] * r;
+
+               err *= (1.0 - r * r);
+
+               /* save this order */
+               for(j = 0; j <= i; j++)
+                       lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+               error[i] = err;
+
+               /* see SF bug #1601812 http://sourceforge.net/tracker/index.php?func=detail&aid=1601812&group_id=13478&atid=113478 */
+               if(err == 0.0) {
+                       *max_order = i+1;
+                       return;
+               }
+       }
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+       unsigned i;
+       FLAC__double cmax;
+       FLAC__int32 qmax, qmin;
+
+       FLAC__ASSERT(precision > 0);
+       FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
+
+       /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+       precision--;
+       qmax = 1 << precision;
+       qmin = -qmax;
+       qmax--;
+
+       /* calc cmax = max( |lp_coeff[i]| ) */
+       cmax = 0.0;
+       for(i = 0; i < order; i++) {
+               const FLAC__double d = fabs(lp_coeff[i]);
+               if(d > cmax)
+                       cmax = d;
+       }
+
+       if(cmax <= 0.0) {
+               /* => coefficients are all 0, which means our constant-detect didn't work */
+               return 2;
+       }
+       else {
+               const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+               const int min_shiftlimit = -max_shiftlimit - 1;
+               int log2cmax;
+
+               (void)frexp(cmax, &log2cmax);
+               log2cmax--;
+               *shift = (int)precision - log2cmax - 1;
+
+               if(*shift > max_shiftlimit)
+                       *shift = max_shiftlimit;
+               else if(*shift < min_shiftlimit)
+                       return 1;
+       }
+
+       if(*shift >= 0) {
+               FLAC__double error = 0.0;
+               FLAC__int32 q;
+               for(i = 0; i < order; i++) {
+                       error += lp_coeff[i] * (1 << *shift);
+#if 1 /* unfortunately lround() is C99 */
+                       if(error >= 0.0)
+                               q = (FLAC__int32)(error + 0.5);
+                       else
+                               q = (FLAC__int32)(error - 0.5);
+#else
+                       q = lround(error);
+#endif
+#ifdef FLAC__OVERFLOW_DETECT
+                       if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+                       else if(q < qmin)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
+#endif
+                       if(q > qmax)
+                               q = qmax;
+                       else if(q < qmin)
+                               q = qmin;
+                       error -= q;
+                       qlp_coeff[i] = q;
+               }
+       }
+       /* negative shift is very rare but due to design flaw, negative shift is
+        * a NOP in the decoder, so it must be handled specially by scaling down
+        * coeffs
+        */
+       else {
+               const int nshift = -(*shift);
+               FLAC__double error = 0.0;
+               FLAC__int32 q;
+#ifdef DEBUG
+               fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax);
+#endif
+               for(i = 0; i < order; i++) {
+                       error += lp_coeff[i] / (1 << nshift);
+#if 1 /* unfortunately lround() is C99 */
+                       if(error >= 0.0)
+                               q = (FLAC__int32)(error + 0.5);
+                       else
+                               q = (FLAC__int32)(error - 0.5);
+#else
+                       q = lround(error);
+#endif
+#ifdef FLAC__OVERFLOW_DETECT
+                       if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+                       else if(q < qmin)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
+#endif
+                       if(q > qmax)
+                               q = qmax;
+                       else if(q < qmin)
+                               q = qmin;
+                       error -= q;
+                       qlp_coeff[i] = q;
+               }
+               *shift = 0;
+       }
+
+       return 0;
+}
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+       FLAC__int64 sumo;
+       unsigned i, j;
+       FLAC__int32 sum;
+       const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+       for(i=0;i<order;i++)
+               fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+       fprintf(stderr,"\n");
+#endif
+       FLAC__ASSERT(order > 0);
+
+       for(i = 0; i < data_len; i++) {
+               sumo = 0;
+               sum = 0;
+               history = data;
+               for(j = 0; j < order; j++) {
+                       sum += qlp_coeff[j] * (*(--history));
+                       sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+                       if(sumo > 2147483647I64 || sumo < -2147483648I64)
+                               fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+                       if(sumo > 2147483647ll || sumo < -2147483648ll)
+                               fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,(long long)sumo);
+#endif
+               }
+               *(residual++) = *(data++) - (sum >> lp_quantization);
+       }
+
+       /* Here's a slower but clearer version:
+       for(i = 0; i < data_len; i++) {
+               sum = 0;
+               for(j = 0; j < order; j++)
+                       sum += qlp_coeff[j] * data[i-j-1];
+               residual[i] = data[i] - (sum >> lp_quantization);
+       }
+       */
+}
+#else /* fully unrolled version for normal use */
+{
+       int i;
+       FLAC__int32 sum;
+
+       FLAC__ASSERT(order > 0);
+       FLAC__ASSERT(order <= 32);
+
+       /*
+        * We do unique versions up to 12th order since that's the subset limit.
+        * Also they are roughly ordered to match frequency of occurrence to
+        * minimize branching.
+        */
+       if(order <= 12) {
+               if(order > 8) {
+                       if(order > 10) {
+                               if(order == 12) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[11] * data[i-12];
+                                               sum += qlp_coeff[10] * data[i-11];
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 11 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[10] * data[i-11];
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 10) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 9 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else if(order > 4) {
+                       if(order > 6) {
+                               if(order == 8) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 7 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 6) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 5 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else {
+                       if(order > 2) {
+                               if(order == 4) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 3 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 2) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               residual[i] = data[i] - (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 1 */
+                                       for(i = 0; i < (int)data_len; i++)
+                                               residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+                               }
+                       }
+               }
+       }
+       else { /* order > 12 */
+               for(i = 0; i < (int)data_len; i++) {
+                       sum = 0;
+                       switch(order) {
+                               case 32: sum += qlp_coeff[31] * data[i-32];
+                               case 31: sum += qlp_coeff[30] * data[i-31];
+                               case 30: sum += qlp_coeff[29] * data[i-30];
+                               case 29: sum += qlp_coeff[28] * data[i-29];
+                               case 28: sum += qlp_coeff[27] * data[i-28];
+                               case 27: sum += qlp_coeff[26] * data[i-27];
+                               case 26: sum += qlp_coeff[25] * data[i-26];
+                               case 25: sum += qlp_coeff[24] * data[i-25];
+                               case 24: sum += qlp_coeff[23] * data[i-24];
+                               case 23: sum += qlp_coeff[22] * data[i-23];
+                               case 22: sum += qlp_coeff[21] * data[i-22];
+                               case 21: sum += qlp_coeff[20] * data[i-21];
+                               case 20: sum += qlp_coeff[19] * data[i-20];
+                               case 19: sum += qlp_coeff[18] * data[i-19];
+                               case 18: sum += qlp_coeff[17] * data[i-18];
+                               case 17: sum += qlp_coeff[16] * data[i-17];
+                               case 16: sum += qlp_coeff[15] * data[i-16];
+                               case 15: sum += qlp_coeff[14] * data[i-15];
+                               case 14: sum += qlp_coeff[13] * data[i-14];
+                               case 13: sum += qlp_coeff[12] * data[i-13];
+                                        sum += qlp_coeff[11] * data[i-12];
+                                        sum += qlp_coeff[10] * data[i-11];
+                                        sum += qlp_coeff[ 9] * data[i-10];
+                                        sum += qlp_coeff[ 8] * data[i- 9];
+                                        sum += qlp_coeff[ 7] * data[i- 8];
+                                        sum += qlp_coeff[ 6] * data[i- 7];
+                                        sum += qlp_coeff[ 5] * data[i- 6];
+                                        sum += qlp_coeff[ 4] * data[i- 5];
+                                        sum += qlp_coeff[ 3] * data[i- 4];
+                                        sum += qlp_coeff[ 2] * data[i- 3];
+                                        sum += qlp_coeff[ 1] * data[i- 2];
+                                        sum += qlp_coeff[ 0] * data[i- 1];
+                       }
+                       residual[i] = data[i] - (sum >> lp_quantization);
+               }
+       }
+}
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+       unsigned i, j;
+       FLAC__int64 sum;
+       const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+       for(i=0;i<order;i++)
+               fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+       fprintf(stderr,"\n");
+#endif
+       FLAC__ASSERT(order > 0);
+
+       for(i = 0; i < data_len; i++) {
+               sum = 0;
+               history = data;
+               for(j = 0; j < order; j++)
+                       sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+               if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+#if defined _MSC_VER
+                       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%I64d\n", i, sum >> lp_quantization);
+#else
+                       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
+#endif
+                       break;
+               }
+               if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+#if defined _MSC_VER
+                       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%I64d, residual=%I64d\n", i, *data, sum >> lp_quantization, (FLAC__int64)(*data) - (sum >> lp_quantization));
+#else
+                       fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*data) - (sum >> lp_quantization)));
+#endif
+                       break;
+               }
+               *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+       }
+}
+#else /* fully unrolled version for normal use */
+{
+       int i;
+       FLAC__int64 sum;
+
+       FLAC__ASSERT(order > 0);
+       FLAC__ASSERT(order <= 32);
+
+       /*
+        * We do unique versions up to 12th order since that's the subset limit.
+        * Also they are roughly ordered to match frequency of occurrence to
+        * minimize branching.
+        */
+       if(order <= 12) {
+               if(order > 8) {
+                       if(order > 10) {
+                               if(order == 12) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+                                               sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 11 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 10) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 9 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else if(order > 4) {
+                       if(order > 6) {
+                               if(order == 8) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 7 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 6) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 5 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else {
+                       if(order > 2) {
+                               if(order == 4) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 3 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 2) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 1 */
+                                       for(i = 0; i < (int)data_len; i++)
+                                               residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+                               }
+                       }
+               }
+       }
+       else { /* order > 12 */
+               for(i = 0; i < (int)data_len; i++) {
+                       sum = 0;
+                       switch(order) {
+                               case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+                               case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+                               case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+                               case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+                               case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+                               case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+                               case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+                               case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+                               case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+                               case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+                               case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+                               case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+                               case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+                               case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+                               case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+                               case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+                               case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+                               case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+                               case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+                               case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+                                        sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+                                        sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                        sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+                                        sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+                                        sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+                                        sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+                                        sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+                                        sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+                                        sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+                                        sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+                                        sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+                                        sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+                       }
+                       residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+               }
+       }
+}
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+       FLAC__int64 sumo;
+       unsigned i, j;
+       FLAC__int32 sum;
+       const FLAC__int32 *r = residual, *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+       fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+       for(i=0;i<order;i++)
+               fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+       fprintf(stderr,"\n");
+#endif
+       FLAC__ASSERT(order > 0);
+
+       for(i = 0; i < data_len; i++) {
+               sumo = 0;
+               sum = 0;
+               history = data;
+               for(j = 0; j < order; j++) {
+                       sum += qlp_coeff[j] * (*(--history));
+                       sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+                       if(sumo > 2147483647I64 || sumo < -2147483648I64)
+                               fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+                       if(sumo > 2147483647ll || sumo < -2147483648ll)
+                               fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,(long long)sumo);
+#endif
+               }
+               *(data++) = *(r++) + (sum >> lp_quantization);
+       }
+
+       /* Here's a slower but clearer version:
+       for(i = 0; i < data_len; i++) {
+               sum = 0;
+               for(j = 0; j < order; j++)
+                       sum += qlp_coeff[j] * data[i-j-1];
+               data[i] = residual[i] + (sum >> lp_quantization);
+       }
+       */
+}
+#else /* fully unrolled version for normal use */
+{
+       int i;
+       FLAC__int32 sum;
+
+       FLAC__ASSERT(order > 0);
+       FLAC__ASSERT(order <= 32);
+
+       /*
+        * We do unique versions up to 12th order since that's the subset limit.
+        * Also they are roughly ordered to match frequency of occurrence to
+        * minimize branching.
+        */
+       if(order <= 12) {
+               if(order > 8) {
+                       if(order > 10) {
+                               if(order == 12) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[11] * data[i-12];
+                                               sum += qlp_coeff[10] * data[i-11];
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 11 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[10] * data[i-11];
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 10) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[9] * data[i-10];
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 9 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[8] * data[i-9];
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else if(order > 4) {
+                       if(order > 6) {
+                               if(order == 8) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[7] * data[i-8];
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 7 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[6] * data[i-7];
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 6) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[5] * data[i-6];
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 5 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[4] * data[i-5];
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else {
+                       if(order > 2) {
+                               if(order == 4) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[3] * data[i-4];
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 3 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[2] * data[i-3];
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 2) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[1] * data[i-2];
+                                               sum += qlp_coeff[0] * data[i-1];
+                                               data[i] = residual[i] + (sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 1 */
+                                       for(i = 0; i < (int)data_len; i++)
+                                               data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+                               }
+                       }
+               }
+       }
+       else { /* order > 12 */
+               for(i = 0; i < (int)data_len; i++) {
+                       sum = 0;
+                       switch(order) {
+                               case 32: sum += qlp_coeff[31] * data[i-32];
+                               case 31: sum += qlp_coeff[30] * data[i-31];
+                               case 30: sum += qlp_coeff[29] * data[i-30];
+                               case 29: sum += qlp_coeff[28] * data[i-29];
+                               case 28: sum += qlp_coeff[27] * data[i-28];
+                               case 27: sum += qlp_coeff[26] * data[i-27];
+                               case 26: sum += qlp_coeff[25] * data[i-26];
+                               case 25: sum += qlp_coeff[24] * data[i-25];
+                               case 24: sum += qlp_coeff[23] * data[i-24];
+                               case 23: sum += qlp_coeff[22] * data[i-23];
+                               case 22: sum += qlp_coeff[21] * data[i-22];
+                               case 21: sum += qlp_coeff[20] * data[i-21];
+                               case 20: sum += qlp_coeff[19] * data[i-20];
+                               case 19: sum += qlp_coeff[18] * data[i-19];
+                               case 18: sum += qlp_coeff[17] * data[i-18];
+                               case 17: sum += qlp_coeff[16] * data[i-17];
+                               case 16: sum += qlp_coeff[15] * data[i-16];
+                               case 15: sum += qlp_coeff[14] * data[i-15];
+                               case 14: sum += qlp_coeff[13] * data[i-14];
+                               case 13: sum += qlp_coeff[12] * data[i-13];
+                                        sum += qlp_coeff[11] * data[i-12];
+                                        sum += qlp_coeff[10] * data[i-11];
+                                        sum += qlp_coeff[ 9] * data[i-10];
+                                        sum += qlp_coeff[ 8] * data[i- 9];
+                                        sum += qlp_coeff[ 7] * data[i- 8];
+                                        sum += qlp_coeff[ 6] * data[i- 7];
+                                        sum += qlp_coeff[ 5] * data[i- 6];
+                                        sum += qlp_coeff[ 4] * data[i- 5];
+                                        sum += qlp_coeff[ 3] * data[i- 4];
+                                        sum += qlp_coeff[ 2] * data[i- 3];
+                                        sum += qlp_coeff[ 1] * data[i- 2];
+                                        sum += qlp_coeff[ 0] * data[i- 1];
+                       }
+                       data[i] = residual[i] + (sum >> lp_quantization);
+               }
+       }
+}
+#endif
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+       unsigned i, j;
+       FLAC__int64 sum;
+       const FLAC__int32 *r = residual, *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+       fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+       for(i=0;i<order;i++)
+               fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+       fprintf(stderr,"\n");
+#endif
+       FLAC__ASSERT(order > 0);
+
+       for(i = 0; i < data_len; i++) {
+               sum = 0;
+               history = data;
+               for(j = 0; j < order; j++)
+                       sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+               if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+#ifdef _MSC_VER
+                       fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%I64d\n", i, sum >> lp_quantization);
+#else
+                       fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
+#endif
+                       break;
+               }
+               if(FLAC__bitmath_silog2_wide((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+#ifdef _MSC_VER
+                       fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%I64d, data=%I64d\n", i, *r, sum >> lp_quantization, (FLAC__int64)(*r) + (sum >> lp_quantization));
+#else
+                       fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *r, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*r) + (sum >> lp_quantization)));
+#endif
+                       break;
+               }
+               *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
+       }
+}
+#else /* fully unrolled version for normal use */
+{
+       int i;
+       FLAC__int64 sum;
+
+       FLAC__ASSERT(order > 0);
+       FLAC__ASSERT(order <= 32);
+
+       /*
+        * We do unique versions up to 12th order since that's the subset limit.
+        * Also they are roughly ordered to match frequency of occurrence to
+        * minimize branching.
+        */
+       if(order <= 12) {
+               if(order > 8) {
+                       if(order > 10) {
+                               if(order == 12) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+                                               sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 11 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 10) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 9 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else if(order > 4) {
+                       if(order > 6) {
+                               if(order == 8) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 7 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 6) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 5 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+               }
+               else {
+                       if(order > 2) {
+                               if(order == 4) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 3 */
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                       }
+                       else {
+                               if(order == 2) {
+                                       for(i = 0; i < (int)data_len; i++) {
+                                               sum = 0;
+                                               sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+                                               sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+                                               data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+                                       }
+                               }
+                               else { /* order == 1 */
+                                       for(i = 0; i < (int)data_len; i++)
+                                               data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+                               }
+                       }
+               }
+       }
+       else { /* order > 12 */
+               for(i = 0; i < (int)data_len; i++) {
+                       sum = 0;
+                       switch(order) {
+                               case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+                               case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+                               case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+                               case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+                               case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+                               case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+                               case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+                               case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+                               case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+                               case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+                               case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+                               case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+                               case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+                               case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+                               case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+                               case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+                               case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+                               case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+                               case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+                               case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+                                        sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+                                        sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+                                        sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+                                        sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+                                        sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+                                        sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+                                        sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+                                        sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+                                        sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+                                        sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+                                        sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+                                        sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+                       }
+                       data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+               }
+       }
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples)
+{
+       FLAC__double error_scale;
+
+       FLAC__ASSERT(total_samples > 0);
+
+       error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
+
+       return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale)
+{
+       if(lpc_error > 0.0) {
+               FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2;
+               if(bps >= 0.0)
+                       return bps;
+               else
+                       return 0.0;
+       }
+       else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
+               return 1e32;
+       }
+       else {
+               return 0.0;
+       }
+}
+
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order)
+{
+       unsigned order, index, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
+       FLAC__double bits, best_bits, error_scale;
+
+       FLAC__ASSERT(max_order > 0);
+       FLAC__ASSERT(total_samples > 0);
+
+       error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
+
+       best_index = 0;
+       best_bits = (unsigned)(-1);
+
+       for(index = 0, order = 1; index < max_order; index++, order++) {
+               bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[index], error_scale) * (FLAC__double)(total_samples - order) + (FLAC__double)(order * overhead_bits_per_order);
+               if(bits < best_bits) {
+                       best_index = index;
+                       best_bits = bits;
+               }
+       }
+
+       return best_index+1; /* +1 since index of lpc_error[] is order-1 */
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/md5.c b/src/libFLAC/md5.c
new file mode 100644 (file)
index 0000000..37cef67
--- /dev/null
@@ -0,0 +1,424 @@
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>            /* for malloc() */
+#include <string.h>            /* for memcpy() */
+
+#include "private/md5.h"
+#include "share/alloc.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+        (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+       register FLAC__uint32 a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+#if WORDS_BIGENDIAN
+//@@@@@@ OPT: use bswap/intrinsics
+static void byteSwap(FLAC__uint32 *buf, unsigned words)
+{
+       register FLAC__uint32 x;
+       do {
+               x = *buf; 
+               x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
+               *buf++ = (x >> 16) | (x << 16);
+       } while (--words);
+}
+static void byteSwapX16(FLAC__uint32 *buf)
+{
+       register FLAC__uint32 x;
+
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+       x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf   = (x >> 16) | (x << 16);
+}
+#else
+#define byteSwap(buf, words)
+#define byteSwapX16(buf)
+#endif
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len)
+{
+       FLAC__uint32 t;
+
+       /* Update byte count */
+
+       t = ctx->bytes[0];
+       if ((ctx->bytes[0] = t + len) < t)
+               ctx->bytes[1]++;        /* Carry from low to high */
+
+       t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
+       if (t > len) {
+               memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
+               return;
+       }
+       /* First chunk is an odd size */
+       memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+       byteSwapX16(ctx->in);
+       FLAC__MD5Transform(ctx->buf, ctx->in);
+       buf += t;
+       len -= t;
+
+       /* Process data in 64-byte chunks */
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               byteSwapX16(ctx->in);
+               FLAC__MD5Transform(ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bytes[0] = 0;
+       ctx->bytes[1] = 0;
+
+       ctx->internal_buf = 0;
+       ctx->capacity = 0;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
+{
+       int count = ctx->bytes[0] & 0x3f;       /* Number of bytes in ctx->in */
+       FLAC__byte *p = (FLAC__byte *)ctx->in + count;
+
+       /* Set the first char of padding to 0x80.  There is always room. */
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 56 bytes (-8..55) */
+       count = 56 - 1 - count;
+
+       if (count < 0) {        /* Padding forces an extra block */
+               memset(p, 0, count + 8);
+               byteSwapX16(ctx->in);
+               FLAC__MD5Transform(ctx->buf, ctx->in);
+               p = (FLAC__byte *)ctx->in;
+               count = 56;
+       }
+       memset(p, 0, count);
+       byteSwap(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ctx->in[14] = ctx->bytes[0] << 3;
+       ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+       FLAC__MD5Transform(ctx->buf, ctx->in);
+
+       byteSwap(ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+       if(0 != ctx->internal_buf) {
+               free(ctx->internal_buf);
+               ctx->internal_buf = 0;
+               ctx->capacity = 0;
+       }
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+       unsigned channel, sample;
+       register FLAC__int32 a_word;
+       register FLAC__byte *buf_ = buf;
+
+#if WORDS_BIGENDIAN
+#else
+       if(channels == 2 && bytes_per_sample == 2) {
+               FLAC__int16 *buf1_ = ((FLAC__int16*)buf_) + 1;
+               memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples);
+               for(sample = 0; sample < samples; sample++, buf1_+=2)
+                       *buf1_ = (FLAC__int16)signal[1][sample];
+       }
+       else if(channels == 1 && bytes_per_sample == 2) {
+               FLAC__int16 *buf1_ = (FLAC__int16*)buf_;
+               for(sample = 0; sample < samples; sample++)
+                       *buf1_++ = (FLAC__int16)signal[0][sample];
+       }
+       else
+#endif
+       if(bytes_per_sample == 2) {
+               if(channels == 2) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                               a_word = signal[1][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else if(channels == 1) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else {
+                       for(sample = 0; sample < samples; sample++) {
+                               for(channel = 0; channel < channels; channel++) {
+                                       a_word = signal[channel][sample];
+                                       *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                                       *buf_++ = (FLAC__byte)a_word;
+                               }
+                       }
+               }
+       }
+       else if(bytes_per_sample == 3) {
+               if(channels == 2) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                               a_word = signal[1][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else if(channels == 1) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else {
+                       for(sample = 0; sample < samples; sample++) {
+                               for(channel = 0; channel < channels; channel++) {
+                                       a_word = signal[channel][sample];
+                                       *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                                       *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                                       *buf_++ = (FLAC__byte)a_word;
+                               }
+                       }
+               }
+       }
+       else if(bytes_per_sample == 1) {
+               if(channels == 2) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word;
+                               a_word = signal[1][sample];
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else if(channels == 1) {
+                       for(sample = 0; sample < samples; sample++) {
+                               a_word = signal[0][sample];
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+               else {
+                       for(sample = 0; sample < samples; sample++) {
+                               for(channel = 0; channel < channels; channel++) {
+                                       a_word = signal[channel][sample];
+                                       *buf_++ = (FLAC__byte)a_word;
+                               }
+                       }
+               }
+       }
+       else { /* bytes_per_sample == 4, maybe optimize more later */
+               for(sample = 0; sample < samples; sample++) {
+                       for(channel = 0; channel < channels; channel++) {
+                               a_word = signal[channel][sample];
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+                               *buf_++ = (FLAC__byte)a_word;
+                       }
+               }
+       }
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+       const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample;
+
+       /* overflow check */
+       if((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample)
+               return false;
+       if((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples)
+               return false;
+
+       if(ctx->capacity < bytes_needed) {
+               FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed);
+               if(0 == tmp) {
+                       free(ctx->internal_buf);
+                       if(0 == (ctx->internal_buf = (FLAC__byte*)safe_malloc_(bytes_needed)))
+                               return false;
+               }
+               ctx->internal_buf = tmp;
+               ctx->capacity = bytes_needed;
+       }
+
+       format_input_(ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+       FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed);
+
+       return true;
+}
diff --git a/src/libFLAC/memory.c b/src/libFLAC/memory.c
new file mode 100644 (file)
index 0000000..4d10097
--- /dev/null
@@ -0,0 +1,221 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+       void *x;
+
+       FLAC__ASSERT(0 != aligned_address);
+
+#ifdef FLAC__ALIGN_MALLOC_DATA
+       /* align on 32-byte (256-bit) boundary */
+       x = safe_malloc_add_2op_(bytes, /*+*/31);
+#ifdef SIZEOF_VOIDP
+#if SIZEOF_VOIDP == 4
+               /* could do  *aligned_address = x + ((unsigned) (32 - (((unsigned)x) & 31))) & 31; */
+               *aligned_address = (void*)(((unsigned)x + 31) & -32);
+#elif SIZEOF_VOIDP == 8
+               *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32)));
+#else
+# error  Unsupported sizeof(void*)
+#endif
+#else
+       /* there's got to be a better way to do this right for all archs */
+       if(sizeof(void*) == sizeof(unsigned))
+               *aligned_address = (void*)(((unsigned)x + 31) & -32);
+       else if(sizeof(void*) == sizeof(FLAC__uint64))
+               *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32)));
+       else
+               return 0;
+#endif
+#else
+       x = safe_malloc_(bytes);
+       *aligned_address = x;
+#endif
+       return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
+{
+       FLAC__int32 *pu; /* unaligned pointer */
+       union { /* union needed to comply with C99 pointer aliasing rules */
+               FLAC__int32 *pa; /* aligned pointer */
+               void        *pv; /* aligned pointer alias */
+       } u;
+
+       FLAC__ASSERT(elements > 0);
+       FLAC__ASSERT(0 != unaligned_pointer);
+       FLAC__ASSERT(0 != aligned_pointer);
+       FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+       if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+               return false;
+
+       pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(*pu) * (size_t)elements, &u.pv);
+       if(0 == pu) {
+               return false;
+       }
+       else {
+               if(*unaligned_pointer != 0)
+                       free(*unaligned_pointer);
+               *unaligned_pointer = pu;
+               *aligned_pointer = u.pa;
+               return true;
+       }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+{
+       FLAC__uint32 *pu; /* unaligned pointer */
+       union { /* union needed to comply with C99 pointer aliasing rules */
+               FLAC__uint32 *pa; /* aligned pointer */
+               void         *pv; /* aligned pointer alias */
+       } u;
+
+       FLAC__ASSERT(elements > 0);
+       FLAC__ASSERT(0 != unaligned_pointer);
+       FLAC__ASSERT(0 != aligned_pointer);
+       FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+       if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+               return false;
+
+       pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+       if(0 == pu) {
+               return false;
+       }
+       else {
+               if(*unaligned_pointer != 0)
+                       free(*unaligned_pointer);
+               *unaligned_pointer = pu;
+               *aligned_pointer = u.pa;
+               return true;
+       }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+{
+       FLAC__uint64 *pu; /* unaligned pointer */
+       union { /* union needed to comply with C99 pointer aliasing rules */
+               FLAC__uint64 *pa; /* aligned pointer */
+               void         *pv; /* aligned pointer alias */
+       } u;
+
+       FLAC__ASSERT(elements > 0);
+       FLAC__ASSERT(0 != unaligned_pointer);
+       FLAC__ASSERT(0 != aligned_pointer);
+       FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+       if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+               return false;
+
+       pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+       if(0 == pu) {
+               return false;
+       }
+       else {
+               if(*unaligned_pointer != 0)
+                       free(*unaligned_pointer);
+               *unaligned_pointer = pu;
+               *aligned_pointer = u.pa;
+               return true;
+       }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
+{
+       unsigned *pu; /* unaligned pointer */
+       union { /* union needed to comply with C99 pointer aliasing rules */
+               unsigned *pa; /* aligned pointer */
+               void     *pv; /* aligned pointer alias */
+       } u;
+
+       FLAC__ASSERT(elements > 0);
+       FLAC__ASSERT(0 != unaligned_pointer);
+       FLAC__ASSERT(0 != aligned_pointer);
+       FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+       if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+               return false;
+
+       pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+       if(0 == pu) {
+               return false;
+       }
+       else {
+               if(*unaligned_pointer != 0)
+                       free(*unaligned_pointer);
+               *unaligned_pointer = pu;
+               *aligned_pointer = u.pa;
+               return true;
+       }
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+{
+       FLAC__real *pu; /* unaligned pointer */
+       union { /* union needed to comply with C99 pointer aliasing rules */
+               FLAC__real *pa; /* aligned pointer */
+               void       *pv; /* aligned pointer alias */
+       } u;
+
+       FLAC__ASSERT(elements > 0);
+       FLAC__ASSERT(0 != unaligned_pointer);
+       FLAC__ASSERT(0 != aligned_pointer);
+       FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+       if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+               return false;
+
+       pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+       if(0 == pu) {
+               return false;
+       }
+       else {
+               if(*unaligned_pointer != 0)
+                       free(*unaligned_pointer);
+               *unaligned_pointer = pu;
+               *aligned_pointer = u.pa;
+               return true;
+       }
+}
+
+#endif
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
new file mode 100644 (file)
index 0000000..15362f7
--- /dev/null
@@ -0,0 +1,3363 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#include <io.h> /* for chmod() */
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static unsigned seek_to_first_metadata_block_(FILE *f);
+
+static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
+static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);
+static void set_file_stats_(const char *filename, struct stat *stats);
+
+static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+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);
+
+typedef struct {
+       FLAC__bool got_error;
+       FLAC__StreamMetadata *object;
+} level0_client_data;
+
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
+{
+       level0_client_data cd;
+       FLAC__StreamDecoder *decoder;
+
+       FLAC__ASSERT(0 != filename);
+
+       cd.got_error = false;
+       cd.object = 0;
+
+       decoder = FLAC__stream_decoder_new();
+
+       if(0 == decoder)
+               return 0;
+
+       FLAC__stream_decoder_set_md5_checking(decoder, false);
+       FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+       FLAC__stream_decoder_set_metadata_respond(decoder, type);
+
+       if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
+               (void)FLAC__stream_decoder_finish(decoder);
+               FLAC__stream_decoder_delete(decoder);
+               return 0;
+       }
+
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+               (void)FLAC__stream_decoder_finish(decoder);
+               FLAC__stream_decoder_delete(decoder);
+               if(0 != cd.object)
+                       FLAC__metadata_object_delete(cd.object);
+               return 0;
+       }
+
+       (void)FLAC__stream_decoder_finish(decoder);
+       FLAC__stream_decoder_delete(decoder);
+
+       return cd.object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+       FLAC__StreamMetadata *object;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != streaminfo);
+
+       object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
+
+       if (object) {
+               /* can just copy the contents since STREAMINFO has no internal structure */
+               *streaminfo = *object;
+               FLAC__metadata_object_delete(object);
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != tags);
+
+       *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       return 0 != *tags;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != cuesheet);
+
+       *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
+
+       return 0 != *cuesheet;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       (void)decoder, (void)frame, (void)buffer, (void)client_data;
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       level0_client_data *cd = (level0_client_data *)client_data;
+       (void)decoder;
+
+       /*
+        * we assume we only get here when the one metadata block we were
+        * looking for was passed to us
+        */
+       if(!cd->got_error && 0 == cd->object) {
+               if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+                       cd->got_error = true;
+       }
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       level0_client_data *cd = (level0_client_data *)client_data;
+       (void)decoder;
+
+       if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+               cd->got_error = true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
+{
+       FLAC__Metadata_SimpleIterator *it;
+       FLAC__uint64 max_area_seen = 0;
+       FLAC__uint64 max_depth_seen = 0;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != picture);
+
+       *picture = 0;
+
+       it = FLAC__metadata_simple_iterator_new();
+       if(0 == it)
+               return false;
+       if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+               FLAC__metadata_simple_iterator_delete(it);
+               return false;
+       }
+       do {
+               if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+                       FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+                       FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+                       /* check constraints */
+                       if(
+                               (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+                               (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+                               (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+                               obj->data.picture.width <= max_width &&
+                               obj->data.picture.height <= max_height &&
+                               obj->data.picture.depth <= max_depth &&
+                               obj->data.picture.colors <= max_colors &&
+                               (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+                       ) {
+                               if(*picture)
+                                       FLAC__metadata_object_delete(*picture);
+                               *picture = obj;
+                               max_area_seen = area;
+                               max_depth_seen = obj->data.picture.depth;
+                       }
+                       else {
+                               FLAC__metadata_object_delete(obj);
+                       }
+               }
+       } while(FLAC__metadata_simple_iterator_next(it));
+
+       FLAC__metadata_simple_iterator_delete(it);
+
+       return (0 != *picture);
+}
+
+
+/****************************************************************************
+ *
+ * Level 1 implementation
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+       FILE *file;
+       char *filename, *tempfile_path_prefix;
+       struct stat stats;
+       FLAC__bool has_stats;
+       FLAC__bool is_writable;
+       FLAC__Metadata_SimpleIteratorStatus status;
+       off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+       off_t first_offset; /* this is the offset to the STREAMINFO block */
+       unsigned depth;
+       /* this is the metadata block header of the current block we are pointing to: */
+       FLAC__bool is_last;
+       FLAC__MetadataType type;
+       unsigned length;
+};
+
+FLAC_API 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",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+       "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
+{
+       FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+       if(0 != iterator) {
+               iterator->file = 0;
+               iterator->filename = 0;
+               iterator->tempfile_path_prefix = 0;
+               iterator->has_stats = false;
+               iterator->is_writable = false;
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+               iterator->first_offset = iterator->offset[0] = -1;
+               iterator->depth = 0;
+       }
+
+       return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+
+       if(0 != iterator->file) {
+               fclose(iterator->file);
+               iterator->file = 0;
+               if(iterator->has_stats)
+                       set_file_stats_(iterator->filename, &iterator->stats);
+       }
+       if(0 != iterator->filename) {
+               free(iterator->filename);
+               iterator->filename = 0;
+       }
+       if(0 != iterator->tempfile_path_prefix) {
+               free(iterator->tempfile_path_prefix);
+               iterator->tempfile_path_prefix = 0;
+       }
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+
+       simple_iterator_free_guts_(iterator);
+       free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__Metadata_SimpleIteratorStatus status;
+
+       FLAC__ASSERT(0 != iterator);
+
+       status = iterator->status;
+       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+       return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+       unsigned ret;
+
+       FLAC__ASSERT(0 != iterator);
+
+       if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
+               iterator->is_writable = false;
+               if(read_only || errno == EACCES) {
+                       if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
+                               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+                               return false;
+                       }
+               }
+               else {
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+                       return false;
+               }
+       }
+       else {
+               iterator->is_writable = true;
+       }
+
+       ret = seek_to_first_metadata_block_(iterator->file);
+       switch(ret) {
+               case 0:
+                       iterator->depth = 0;
+                       iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
+                       return read_metadata_block_header_(iterator);
+               case 1:
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               case 2:
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+                       return false;
+               case 3:
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+                       return false;
+               default:
+                       FLAC__ASSERT(0);
+                       return false;
+       }
+}
+
+#if 0
+@@@ If we decide to finish implementing this, put this comment back in metadata.h
+/*
+ * The 'tempfile_path_prefix' allows you to specify a directory where
+ * tempfiles should go.  Remember that if your metadata edits cause the
+ * FLAC file to grow, the entire file will have to be rewritten.  If
+ * 'tempfile_path_prefix' is NULL, the temp file will be written in the
+ * same directory as the original FLAC file.  This makes replacing the
+ * original with the tempfile fast but requires extra space in the same
+ * partition for the tempfile.  If space is a problem, you can pass a
+ * directory name belonging to a different partition in
+ * 'tempfile_path_prefix'.  Note that you should use the forward slash
+ * '/' as the directory separator.  A trailing slash is not needed; it
+ * will be added automatically.
+ */
+FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
+#endif
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+       const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != filename);
+
+       simple_iterator_free_guts_(iterator);
+
+       if(!read_only && preserve_file_stats)
+               iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+       if(0 == (iterator->filename = strdup(filename))) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       if(iterator->is_last)
+               return false;
+
+       if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       iterator->offset[iterator->depth] = ftello(iterator->file);
+
+       return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+       off_t this_offset;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       if(iterator->offset[iterator->depth] == iterator->first_offset)
+               return false;
+
+       if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+       this_offset = iterator->first_offset;
+       if(!read_metadata_block_header_(iterator))
+               return false;
+
+       /* we ignore any error from ftello() and catch it in fseeko() */
+       while(ftello(iterator->file) + (off_t)iterator->length < iterator->offset[iterator->depth]) {
+               if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+                       return false;
+               }
+               this_offset = ftello(iterator->file);
+               if(!read_metadata_block_header_(iterator))
+                       return false;
+       }
+
+       iterator->offset[iterator->depth] = this_offset;
+
+       return true;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       return iterator->is_last;
+}
+
+/*@@@@add to tests*/
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       return iterator->offset[iterator->depth];
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       return iterator->type;
+}
+
+/*@@@@add to tests*/
+FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       return iterator->length;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id)
+{
+       const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+       FLAC__ASSERT(0 != id);
+
+       if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+               return false;
+       }
+
+       if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+               return false;
+       }
+
+       /* back up */
+       if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       if(0 != block) {
+               block->is_last = iterator->is_last;
+               block->length = iterator->length;
+
+               if(!read_metadata_block_data_(iterator, block)) {
+                       FLAC__metadata_object_delete(block);
+                       return 0;
+               }
+
+               /* back up to the beginning of the block data to stay consistent */
+               if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+                       FLAC__metadata_object_delete(block);
+                       return 0;
+               }
+       }
+       else
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+       FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
+       FLAC__bool ret;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+       FLAC__ASSERT(0 != block);
+
+       if(!iterator->is_writable) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+               return false;
+       }
+
+       if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               if(iterator->type != block->type) {
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+                       return false;
+               }
+       }
+
+       block->is_last = iterator->is_last;
+
+       if(iterator->length == block->length)
+               return write_metadata_block_stationary_(iterator, block);
+       else if(iterator->length > block->length) {
+               if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+                       ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+                       FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+                       FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       return ret;
+               }
+               else {
+                       ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+                       FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+                       FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       return ret;
+               }
+       }
+       else /* iterator->length < block->length */ {
+               unsigned padding_leftover = 0;
+               FLAC__bool padding_is_last = false;
+               if(use_padding) {
+                       /* first see if we can even use padding */
+                       if(iterator->is_last) {
+                               use_padding = false;
+                       }
+                       else {
+                               const unsigned extra_padding_bytes_required = block->length - iterator->length;
+                               simple_iterator_push_(iterator);
+                               if(!FLAC__metadata_simple_iterator_next(iterator)) {
+                                       (void)simple_iterator_pop_(iterator);
+                                       return false;
+                               }
+                               if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+                                       use_padding = false;
+                               }
+                               else {
+                                       if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+                                               padding_leftover = 0;
+                                               block->is_last = iterator->is_last;
+                                       }
+                                       else if(iterator->length < extra_padding_bytes_required)
+                                               use_padding = false;
+                                       else {
+                                               padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+                                               padding_is_last = iterator->is_last;
+                                               block->is_last = false;
+                                       }
+                               }
+                               if(!simple_iterator_pop_(iterator))
+                                       return false;
+                       }
+               }
+               if(use_padding) {
+                       if(padding_leftover == 0) {
+                               ret = write_metadata_block_stationary_(iterator, block);
+                               FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+                               FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                               return ret;
+                       }
+                       else {
+                               FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+                               ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+                               FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+                               FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                               return ret;
+                       }
+               }
+               else {
+                       ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+                       FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+                       FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       return ret;
+               }
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+       unsigned padding_leftover = 0;
+       FLAC__bool padding_is_last = false;
+
+       FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
+       FLAC__bool ret;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+       FLAC__ASSERT(0 != block);
+
+       if(!iterator->is_writable)
+               return false;
+
+       if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+               return false;
+       }
+
+       block->is_last = iterator->is_last;
+
+       if(use_padding) {
+               /* first see if we can even use padding */
+               if(iterator->is_last) {
+                       use_padding = false;
+               }
+               else {
+                       simple_iterator_push_(iterator);
+                       if(!FLAC__metadata_simple_iterator_next(iterator)) {
+                               (void)simple_iterator_pop_(iterator);
+                               return false;
+                       }
+                       if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+                               use_padding = false;
+                       }
+                       else {
+                               if(iterator->length == block->length) {
+                                       padding_leftover = 0;
+                                       block->is_last = iterator->is_last;
+                               }
+                               else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+                                       use_padding = false;
+                               else {
+                                       padding_leftover = iterator->length - block->length;
+                                       padding_is_last = iterator->is_last;
+                                       block->is_last = false;
+                               }
+                       }
+                       if(!simple_iterator_pop_(iterator))
+                               return false;
+               }
+       }
+       if(use_padding) {
+               /* move to the next block, which is suitable padding */
+               if(!FLAC__metadata_simple_iterator_next(iterator))
+                       return false;
+               if(padding_leftover == 0) {
+                       ret = write_metadata_block_stationary_(iterator, block);
+                       FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+                       FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       return ret;
+               }
+               else {
+                       FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+                       FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+                       FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+                       return ret;
+               }
+       }
+       else {
+               ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+               FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+               FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+               return ret;
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+       FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
+       FLAC__bool ret;
+
+       if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+               return false;
+       }
+
+       if(use_padding) {
+               FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+               if(0 == padding) {
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               padding->length = iterator->length;
+               if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+                       FLAC__metadata_object_delete(padding);
+                       return false;
+               }
+               FLAC__metadata_object_delete(padding);
+               if(!FLAC__metadata_simple_iterator_prev(iterator))
+                       return false;
+               FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
+               FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
+               return true;
+       }
+       else {
+               ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
+               FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
+               FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
+               return ret;
+       }
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+       FLAC__StreamMetadata *data;
+       struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+       char *filename; /* will be NULL if using callbacks */
+       FLAC__bool is_ogg;
+       FLAC__Metadata_Node *head;
+       FLAC__Metadata_Node *tail;
+       unsigned nodes;
+       FLAC__Metadata_ChainStatus status;
+       off_t first_offset, last_offset;
+       /*
+        * This is the length of the chain initially read from the FLAC file.
+        * it is used to compare against the current length to decide whether
+        * or not the whole file has to be rewritten.
+        */
+       off_t initial_length;
+       /* @@@ hacky, these are currently only needed by ogg reader */
+       FLAC__IOHandle handle;
+       FLAC__IOCallback_Read read_cb;
+};
+
+struct FLAC__Metadata_Iterator {
+       FLAC__Metadata_Chain *chain;
+       FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+       "FLAC__METADATA_CHAIN_STATUS_OK",
+       "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+       "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+       "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+       "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+       "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+       "FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+       "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+       "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+       "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_(void)
+{
+       return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+       FLAC__ASSERT(0 != node);
+       if(0 != node->data)
+               FLAC__metadata_object_delete(node->data);
+       free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+       FLAC__ASSERT(0 != chain);
+
+       chain->filename = 0;
+       chain->is_ogg = false;
+       chain->head = chain->tail = 0;
+       chain->nodes = 0;
+       chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+       chain->initial_length = 0;
+       chain->read_cb = 0;
+}
+
+static void chain_clear_(FLAC__Metadata_Chain *chain)
+{
+       FLAC__Metadata_Node *node, *next;
+
+       FLAC__ASSERT(0 != chain);
+
+       for(node = chain->head; node; ) {
+               next = node->next;
+               node_delete_(node);
+               node = next;
+       }
+
+       if(0 != chain->filename)
+               free(chain->filename);
+
+       chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != node);
+       FLAC__ASSERT(0 != node->data);
+
+       node->next = node->prev = 0;
+       node->data->is_last = true;
+       if(0 != chain->tail)
+               chain->tail->data->is_last = false;
+
+       if(0 == chain->head)
+               chain->head = node;
+       else {
+               FLAC__ASSERT(0 != chain->tail);
+               chain->tail->next = node;
+               node->prev = chain->tail;
+       }
+       chain->tail = node;
+       chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != node);
+
+       if(node == chain->head)
+               chain->head = node->next;
+       else
+               node->prev->next = node->next;
+
+       if(node == chain->tail)
+               chain->tail = node->prev;
+       else
+               node->next->prev = node->prev;
+
+       if(0 != chain->tail)
+               chain->tail->data->is_last = true;
+
+       chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+       chain_remove_node_(chain, node);
+       node_delete_(node);
+}
+
+static off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+       const FLAC__Metadata_Node *node;
+       off_t length = 0;
+       for(node = chain->head; node; node = node->next)
+               length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+       return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+       FLAC__ASSERT(0 != node);
+       FLAC__ASSERT(0 != node->data);
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+       FLAC__ASSERT(0 != iterator->chain);
+       FLAC__ASSERT(0 != iterator->chain->head);
+       FLAC__ASSERT(0 != iterator->chain->tail);
+
+       node->data->is_last = false;
+
+       node->prev = iterator->current->prev;
+       node->next = iterator->current;
+
+       if(0 == node->prev)
+               iterator->chain->head = node;
+       else
+               node->prev->next = node;
+
+       iterator->current->prev = node;
+
+       iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+       FLAC__ASSERT(0 != node);
+       FLAC__ASSERT(0 != node->data);
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+       FLAC__ASSERT(0 != iterator->chain);
+       FLAC__ASSERT(0 != iterator->chain->head);
+       FLAC__ASSERT(0 != iterator->chain->tail);
+
+       iterator->current->data->is_last = false;
+
+       node->prev = iterator->current;
+       node->next = iterator->current->next;
+
+       if(0 == node->next)
+               iterator->chain->tail = node;
+       else
+               node->next->prev = node;
+
+       node->prev->next = node;
+
+       iterator->chain->tail->data->is_last = true;
+
+       iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+       if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+               const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+               node->data->length += growth;
+
+               chain_delete_node_(chain, node->next);
+               return true;
+       }
+       else
+               return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+       off_t current_length = chain_calculate_length_(chain);
+
+       if(use_padding) {
+               /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+               if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+                       const off_t delta = chain->initial_length - current_length;
+                       chain->tail->data->length += delta;
+                       current_length += delta;
+                       FLAC__ASSERT(current_length == chain->initial_length);
+               }
+               /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+               else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+                       FLAC__StreamMetadata *padding;
+                       FLAC__Metadata_Node *node;
+                       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
+                               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+                               return 0;
+                       }
+                       padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
+                       if(0 == (node = node_new_())) {
+                               FLAC__metadata_object_delete(padding);
+                               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+                               return 0;
+                       }
+                       node->data = padding;
+                       chain_append_node_(chain, node);
+                       current_length = chain_calculate_length_(chain);
+                       FLAC__ASSERT(current_length == chain->initial_length);
+               }
+               /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+               else if(current_length > chain->initial_length) {
+                       const off_t delta = current_length - chain->initial_length;
+                       if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+                               /* if the delta is exactly the size of the last padding block, remove the padding block */
+                               if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+                                       chain_delete_node_(chain, chain->tail);
+                                       current_length = chain_calculate_length_(chain);
+                                       FLAC__ASSERT(current_length == chain->initial_length);
+                               }
+                               /* if there is at least 'delta' bytes of padding, trim the padding down */
+                               else if((off_t)chain->tail->data->length >= delta) {
+                                       chain->tail->data->length -= delta;
+                                       current_length -= delta;
+                                       FLAC__ASSERT(current_length == chain->initial_length);
+                               }
+                       }
+               }
+       }
+
+       return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+       FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != chain);
+
+       /* we assume we're already at the beginning of the file */
+
+       switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+               case 0:
+                       break;
+               case 1:
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+                       return false;
+               case 2:
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+                       return false;
+               case 3:
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+                       return false;
+               default:
+                       FLAC__ASSERT(0);
+                       return false;
+       }
+
+       {
+               FLAC__int64 pos = tell_cb(handle);
+               if(pos < 0) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+                       return false;
+               }
+               chain->first_offset = (off_t)pos;
+       }
+
+       {
+               FLAC__bool is_last;
+               FLAC__MetadataType type;
+               unsigned length;
+
+               do {
+                       node = node_new_();
+                       if(0 == node) {
+                               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+                               return false;
+                       }
+
+                       if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+                               chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+                               return false;
+                       }
+
+                       node->data = FLAC__metadata_object_new(type);
+                       if(0 == node->data) {
+                               node_delete_(node);
+                               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+                               return false;
+                       }
+
+                       node->data->is_last = is_last;
+                       node->data->length = length;
+
+                       chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+                       if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+                               node_delete_(node);
+                               return false;
+                       }
+                       chain_append_node_(chain, node);
+               } while(!is_last);
+       }
+
+       {
+               FLAC__int64 pos = tell_cb(handle);
+               if(pos < 0) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+                       return false;
+               }
+               chain->last_offset = (off_t)pos;
+       }
+
+       chain->initial_length = chain_calculate_length_(chain);
+
+       return true;
+}
+
+static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+       (void)decoder;
+       if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
+               *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
+               if(*bytes == 0)
+                       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+               else
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+       }
+       else
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       (void)decoder, (void)frame, (void)buffer, (void)client_data;
+       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+       FLAC__Metadata_Node *node;
+
+       (void)decoder;
+
+       node = node_new_();
+       if(0 == node) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+               return;
+       }
+
+       node->data = FLAC__metadata_object_clone(metadata);
+       if(0 == node->data) {
+               node_delete_(node);
+               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+               return;
+       }
+
+       chain_append_node_(chain, node);
+}
+
+static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+       (void)decoder, (void)status;
+       chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+}
+
+static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
+{
+       FLAC__StreamDecoder *decoder;
+
+       FLAC__ASSERT(0 != chain);
+
+       /* we assume we're already at the beginning of the file */
+
+       chain->handle = handle;
+       chain->read_cb = read_cb;
+       if(0 == (decoder = FLAC__stream_decoder_new())) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       FLAC__stream_decoder_set_metadata_respond_all(decoder);
+       if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               FLAC__stream_decoder_delete(decoder);
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+               return false;
+       }
+
+       chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+       if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+               FLAC__stream_decoder_delete(decoder);
+               return false;
+       }
+
+       FLAC__stream_decoder_delete(decoder);
+
+       chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+       chain->initial_length = chain_calculate_length_(chain);
+
+       return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
+{
+       FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != chain->head);
+
+       if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       for(node = chain->head; node; node = node->next) {
+               if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+                       return false;
+               }
+               if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+                       return false;
+               }
+       }
+
+       /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+       chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+       return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+       FILE *file;
+       FLAC__bool ret;
+
+       FLAC__ASSERT(0 != chain->filename);
+
+       if(0 == (file = fopen(chain->filename, "r+b"))) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+               return false;
+       }
+
+       /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+       ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+       fclose(file);
+
+       return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+       FILE *f, *tempfile;
+       char *tempfilename;
+       FLAC__Metadata_SimpleIteratorStatus status;
+       const FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != chain->filename);
+       FLAC__ASSERT(0 != chain->head);
+
+       /* copy the file prefix (data up to first metadata block */
+       if(0 == (f = fopen(chain->filename, "rb"))) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+               return false;
+       }
+       if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
+               chain->status = get_equivalent_status_(status);
+               cleanup_tempfile_(&tempfile, &tempfilename);
+               return false;
+       }
+       if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+               chain->status = get_equivalent_status_(status);
+               cleanup_tempfile_(&tempfile, &tempfilename);
+               return false;
+       }
+
+       /* write the metadata */
+       for(node = chain->head; node; node = node->next) {
+               if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+                       chain->status = get_equivalent_status_(status);
+                       return false;
+               }
+               if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+                       chain->status = get_equivalent_status_(status);
+                       return false;
+               }
+       }
+       /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+       /* copy the file postfix (everything after the metadata) */
+       if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+               cleanup_tempfile_(&tempfile, &tempfilename);
+               chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               return false;
+       }
+       if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+               cleanup_tempfile_(&tempfile, &tempfilename);
+               chain->status = get_equivalent_status_(status);
+               return false;
+       }
+
+       /* move the tempfile on top of the original */
+       (void)fclose(f);
+       if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+               return false;
+
+       return true;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+       FLAC__Metadata_SimpleIteratorStatus status;
+       const FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 == chain->filename);
+       FLAC__ASSERT(0 != chain->head);
+
+       /* copy the file prefix (data up to first metadata block */
+       if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+               chain->status = get_equivalent_status_(status);
+               return false;
+       }
+
+       /* write the metadata */
+       for(node = chain->head; node; node = node->next) {
+               if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+                       return false;
+               }
+               if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+                       chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+                       return false;
+               }
+       }
+       /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+       /* copy the file postfix (everything after the metadata) */
+       if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               return false;
+       }
+       if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+               chain->status = get_equivalent_status_(status);
+               return false;
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
+{
+       FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
+
+       if(0 != chain)
+               chain_init_(chain);
+
+       return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+       FLAC__ASSERT(0 != chain);
+
+       chain_clear_(chain);
+
+       free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+       FLAC__Metadata_ChainStatus status;
+
+       FLAC__ASSERT(0 != chain);
+
+       status = chain->status;
+       chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+       return status;
+}
+
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
+{
+       FILE *file;
+       FLAC__bool ret;
+
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != filename);
+
+       chain_clear_(chain);
+
+       if(0 == (chain->filename = strdup(filename))) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       chain->is_ogg = is_ogg;
+
+       if(0 == (file = fopen(filename, "rb"))) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+               return false;
+       }
+
+       /* the function also sets chain->status for us */
+       ret = is_ogg?
+               chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
+               chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
+       ;
+
+       fclose(file);
+
+       return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+{
+       return chain_read_(chain, filename, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
+{
+       return chain_read_(chain, filename, /*is_ogg=*/true);
+}
+
+static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
+{
+       FLAC__bool ret;
+
+       FLAC__ASSERT(0 != chain);
+
+       chain_clear_(chain);
+
+       if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+               return false;
+       }
+
+       chain->is_ogg = is_ogg;
+
+       /* rewind */
+       if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       /* the function also sets chain->status for us */
+       ret = is_ogg?
+               chain_read_ogg_cb_(chain, handle, callbacks.read) :
+               chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
+       ;
+
+       return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+       return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+       return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+       /* This does all the same checks that are in chain_prepare_for_write_()
+        * but doesn't actually alter the chain.  Make sure to update the logic
+        * here if chain_prepare_for_write_() changes.
+        */
+       const off_t current_length = chain_calculate_length_(chain);
+
+       FLAC__ASSERT(0 != chain);
+
+       if(use_padding) {
+               /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+               if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING)
+                       return false;
+               /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+               else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length)
+                       return false;
+               /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+               else if(current_length > chain->initial_length) {
+                       const off_t delta = current_length - chain->initial_length;
+                       if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+                               /* if the delta is exactly the size of the last padding block, remove the padding block */
+                               if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta)
+                                       return false;
+                               /* if there is at least 'delta' bytes of padding, trim the padding down */
+                               else if((off_t)chain->tail->data->length >= delta)
+                                       return false;
+                       }
+               }
+       }
+
+       return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+       struct stat stats;
+       const char *tempfile_path_prefix = 0;
+       off_t current_length;
+
+       FLAC__ASSERT(0 != chain);
+
+       if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+               return false;
+       }
+
+       if (0 == chain->filename) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+               return false;
+       }
+
+       current_length = chain_prepare_for_write_(chain, use_padding);
+
+       /* a return value of 0 means there was an error; chain->status is already set */
+       if (0 == current_length)
+               return false;
+
+       if(preserve_file_stats)
+               get_file_stats_(chain->filename, &stats);
+
+       if(current_length == chain->initial_length) {
+               if(!chain_rewrite_metadata_in_place_(chain))
+                       return false;
+       }
+       else {
+               if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+                       return false;
+
+               /* recompute lengths and offsets */
+               {
+                       const FLAC__Metadata_Node *node;
+                       chain->initial_length = current_length;
+                       chain->last_offset = chain->first_offset;
+                       for(node = chain->head; node; node = node->next)
+                               chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+               }
+       }
+
+       if(preserve_file_stats)
+               set_file_stats_(chain->filename, &stats);
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+       off_t current_length;
+
+       FLAC__ASSERT(0 != chain);
+
+       if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+               return false;
+       }
+
+       if (0 != chain->filename) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+               return false;
+       }
+
+       if (0 == callbacks.write || 0 == callbacks.seek) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+               return false;
+       }
+
+       if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+               return false;
+       }
+
+       current_length = chain_prepare_for_write_(chain, use_padding);
+
+       /* a return value of 0 means there was an error; chain->status is already set */
+       if (0 == current_length)
+               return false;
+
+       FLAC__ASSERT(current_length == chain->initial_length);
+
+       return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+       off_t current_length;
+
+       FLAC__ASSERT(0 != chain);
+
+       if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+               return false;
+       }
+
+       if (0 != chain->filename) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+               return false;
+       }
+
+       if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+               return false;
+       }
+       if (0 == temp_callbacks.write) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+               return false;
+       }
+
+       if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+               return false;
+       }
+
+       current_length = chain_prepare_for_write_(chain, use_padding);
+
+       /* a return value of 0 means there was an error; chain->status is already set */
+       if (0 == current_length)
+               return false;
+
+       FLAC__ASSERT(current_length != chain->initial_length);
+
+       /* rewind */
+       if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+               chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+               return false;
+
+       /* recompute lengths and offsets */
+       {
+               const FLAC__Metadata_Node *node;
+               chain->initial_length = current_length;
+               chain->last_offset = chain->first_offset;
+               for(node = chain->head; node; node = node->next)
+                       chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+       }
+
+       return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+       FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != chain);
+
+       for(node = chain->head; node; ) {
+               if(!chain_merge_adjacent_padding_(chain, node))
+                       node = node->next;
+       }
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+       FLAC__Metadata_Node *node, *save;
+       unsigned i;
+
+       FLAC__ASSERT(0 != chain);
+
+       /*
+        * Don't try and be too smart... this simple algo is good enough for
+        * the small number of nodes that we deal with.
+        */
+       for(i = 0, node = chain->head; i < chain->nodes; i++) {
+               if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+                       save = node->next;
+                       chain_remove_node_(chain, node);
+                       chain_append_node_(chain, node);
+                       node = save;
+               }
+               else {
+                       node = node->next;
+               }
+       }
+
+       FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
+{
+       FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+       /* calloc() implies:
+               iterator->current = 0;
+               iterator->chain = 0;
+       */
+
+       return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+
+       free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != chain);
+       FLAC__ASSERT(0 != chain->head);
+
+       iterator->chain = chain;
+       iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+
+       if(0 == iterator->current || 0 == iterator->current->next)
+               return false;
+
+       iterator->current = iterator->current->next;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+
+       if(0 == iterator->current || 0 == iterator->current->prev)
+               return false;
+
+       iterator->current = iterator->current->prev;
+       return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+       FLAC__ASSERT(0 != iterator->current->data);
+
+       return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+
+       return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != block);
+       return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+       FLAC__Metadata_Node *save;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+
+       if(0 == iterator->current->prev) {
+               FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+               return false;
+       }
+
+       save = iterator->current->prev;
+
+       if(replace_with_padding) {
+               FLAC__metadata_object_delete_data(iterator->current->data);
+               iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+       }
+       else {
+               chain_delete_node_(iterator->chain, iterator->current);
+       }
+
+       iterator->current = save;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+       FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+       FLAC__ASSERT(0 != block);
+
+       if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+               return false;
+
+       if(0 == iterator->current->prev) {
+               FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+               return false;
+       }
+
+       if(0 == (node = node_new_()))
+               return false;
+
+       node->data = block;
+       iterator_insert_node_(iterator, node);
+       iterator->current = node;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+       FLAC__Metadata_Node *node;
+
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->current);
+       FLAC__ASSERT(0 != block);
+
+       if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+               return false;
+
+       if(0 == (node = node_new_()))
+               return false;
+
+       node->data = block;
+       iterator_insert_node_after_(iterator, node);
+       iterator->current = node;
+       return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+       unsigned i;
+
+       b += bytes;
+
+       for(i = 0; i < bytes; i++) {
+               *(--b) = (FLAC__byte)(val & 0xff);
+               val >>= 8;
+       }
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+       unsigned i;
+
+       for(i = 0; i < bytes; i++) {
+               *(b++) = (FLAC__byte)(val & 0xff);
+               val >>= 8;
+       }
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
+{
+       unsigned i;
+
+       b += bytes;
+
+       for(i = 0; i < bytes; i++) {
+               *(--b) = (FLAC__byte)(val & 0xff);
+               val >>= 8;
+       }
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
+{
+       FLAC__uint32 ret = 0;
+       unsigned i;
+
+       for(i = 0; i < bytes; i++)
+               ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+       return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
+{
+       FLAC__uint32 ret = 0;
+       unsigned i;
+
+       b += bytes;
+
+       for(i = 0; i < bytes; i++)
+               ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+       return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
+{
+       FLAC__uint64 ret = 0;
+       unsigned i;
+
+       for(i = 0; i < bytes; i++)
+               ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+       return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != iterator);
+       FLAC__ASSERT(0 != iterator->file);
+
+       iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+       return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
+{
+       FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+       if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+               return false;
+
+       *is_last = raw_header[0] & 0x80? true : false;
+       *type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+       *length = unpack_uint32_(raw_header + 1, 3);
+
+       /* Note that we don't check:
+        *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+        * we just will read in an opaque block
+        */
+
+       return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+       switch(block->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+               case FLAC__METADATA_TYPE_PADDING:
+                       return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment);
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+               case FLAC__METADATA_TYPE_PICTURE:
+                       return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
+               default:
+                       return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
+       }
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+       FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+       if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+       b = buffer;
+
+       /* we are using hardcoded numbers for simplicity but we should
+        * probably eventually write a bit-level unpacker and use the
+        * _STREAMINFO_ constants.
+        */
+       block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+       block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+       block->min_framesize = unpack_uint32_(b, 3); b += 3;
+       block->max_framesize = unpack_uint32_(b, 3); b += 3;
+       block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
+       block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
+       block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
+       block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+       memcpy(block->md5sum, b+8, 16);
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+       (void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+       if(0 != seek_cb(handle, block_length, SEEK_CUR))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+       const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+       if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+       if(block_length < id_bytes)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+       block_length -= id_bytes;
+
+       if(block_length == 0) {
+               block->data = 0;
+       }
+       else {
+               if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+               if(read_cb(block->data, 1, block_length, handle) != block_length)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
+{
+       unsigned i;
+       FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+       FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
+
+       block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+       if(block->num_points == 0)
+               block->points = 0;
+       else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)safe_malloc_mul_2op_(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       for(i = 0; i < block->num_points; i++) {
+               if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+               /* some MAGIC NUMBERs here */
+               block->points[i].sample_number = unpack_uint64_(buffer, 8);
+               block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+               block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+       const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+       FLAC__byte buffer[4]; /* magic number is asserted below */
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer));
+
+       if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
+
+       if(0 != entry->entry)
+               free(entry->entry);
+
+       if(entry->length == 0) {
+               entry->entry = 0;
+       }
+       else {
+               if(0 == (entry->entry = (FLAC__byte*)safe_malloc_add_2op_(entry->length, /*+*/1)))
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+               if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+               entry->entry[entry->length] = '\0';
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block)
+{
+       unsigned i;
+       FLAC__Metadata_SimpleIteratorStatus status;
+       const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+       FLAC__byte buffer[4]; /* magic number is asserted below */
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
+
+       if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
+               return status;
+
+       if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
+
+       if(block->num_comments == 0) {
+               block->comments = 0;
+       }
+       else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry))))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       for(i = 0; i < block->num_comments; i++) {
+               if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i)))
+                       return status;
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+       unsigned i, len;
+       FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+       FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       track->offset = unpack_uint64_(buffer, len);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+       if(read_cb(track->isrc, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+       FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+       len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
+       track->type = buffer[0] >> 7;
+       track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+       if(track->num_indices == 0) {
+               track->indices = 0;
+       }
+       else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       for(i = 0; i < track->num_indices; i++) {
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+               if(read_cb(buffer, 1, len, handle) != len)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+               track->indices[i].offset = unpack_uint64_(buffer, len);
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+               if(read_cb(buffer, 1, len, handle) != len)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+               track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+               if(read_cb(buffer, 1, len, handle) != len)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+       unsigned i, len;
+       FLAC__Metadata_SimpleIteratorStatus status;
+       FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+       FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
+       FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+       if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->lead_in = unpack_uint64_(buffer, len);
+
+       FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+       len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->is_cd = buffer[0]&0x80? true : false;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->num_tracks = unpack_uint32_(buffer, len);
+
+       if(block->num_tracks == 0) {
+               block->tracks = 0;
+       }
+       else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       for(i = 0; i < block->num_tracks; i++) {
+               if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+                       return status;
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+       FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+       FLAC__ASSERT(0 != data);
+       FLAC__ASSERT(length_len%8 == 0);
+
+       length_len /= 8; /* convert to bytes */
+
+       FLAC__ASSERT(sizeof(buffer) >= length_len);
+
+       if(read_cb(buffer, 1, length_len, handle) != length_len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       *length = unpack_uint32_(buffer, length_len);
+
+       if(0 != *data)
+               free(*data);
+
+       if(0 == (*data = (FLAC__byte*)safe_malloc_add_2op_(*length, /*+*/1)))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       if(*length > 0) {
+               if(read_cb(*data, 1, *length, handle) != *length)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       }
+
+       (*data)[*length] = '\0';
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+       FLAC__Metadata_SimpleIteratorStatus status;
+       FLAC__byte buffer[4]; /* asserted below that this is big enough */
+       FLAC__uint32 len;
+
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
+
+       if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+               return status;
+
+       if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+               return status;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->width = unpack_uint32_(buffer, len);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->height = unpack_uint32_(buffer, len);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->depth = unpack_uint32_(buffer, len);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
+       if(read_cb(buffer, 1, len, handle) != len)
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       block->colors = unpack_uint32_(buffer, len);
+
+       /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+       if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+               return status;
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+       if(block_length == 0) {
+               block->data = 0;
+       }
+       else {
+               if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+               if(read_cb(block->data, 1, block_length, handle) != block_length)
+                       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+       }
+
+       return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != file);
+       FLAC__ASSERT(0 != status);
+
+       if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != file);
+       FLAC__ASSERT(0 != status);
+
+       if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+               return true;
+       }
+       else {
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+               return false;
+       }
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+       FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+       FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+
+       buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+       pack_uint32_(block->length, buffer + 1, 3);
+
+       if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != block);
+
+       switch(block->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+               case FLAC__METADATA_TYPE_PADDING:
+                       return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+               case FLAC__METADATA_TYPE_PICTURE:
+                       return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
+               default:
+                       return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+       }
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+       FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+       const unsigned channels1 = block->channels - 1;
+       const unsigned bps1 = block->bits_per_sample - 1;
+
+       /* we are using hardcoded numbers for simplicity but we should
+        * probably eventually write a bit-level packer and use the
+        * _STREAMINFO_ constants.
+        */
+       pack_uint32_(block->min_blocksize, buffer, 2);
+       pack_uint32_(block->max_blocksize, buffer+2, 2);
+       pack_uint32_(block->min_framesize, buffer+4, 3);
+       pack_uint32_(block->max_framesize, buffer+7, 3);
+       buffer[10] = (block->sample_rate >> 12) & 0xff;
+       buffer[11] = (block->sample_rate >> 4) & 0xff;
+       buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
+       buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+       pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+       memcpy(buffer+18, block->md5sum, 16);
+
+       if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+       unsigned i, n = block_length;
+       FLAC__byte buffer[1024];
+
+       (void)block;
+
+       memset(buffer, 0, 1024);
+
+       for(i = 0; i < n/1024; i++)
+               if(write_cb(buffer, 1, 1024, handle) != 1024)
+                       return false;
+
+       n %= 1024;
+
+       if(write_cb(buffer, 1, n, handle) != n)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+       const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+       if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+               return false;
+
+       block_length -= id_bytes;
+
+       if(write_cb(block->data, 1, block_length, handle) != block_length)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+       unsigned i;
+       FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+       for(i = 0; i < block->num_points; i++) {
+               /* some MAGIC NUMBERs here */
+               pack_uint64_(block->points[i].sample_number, buffer, 8);
+               pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+               pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+               if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+                       return false;
+       }
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+       unsigned i;
+       const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+       const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+       FLAC__byte buffer[4]; /* magic number is asserted below */
+
+       FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer));
+
+       pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
+       if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+               return false;
+       if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+               return false;
+
+       pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+       if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+               return false;
+
+       for(i = 0; i < block->num_comments; i++) {
+               pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+               if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+                       return false;
+               if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+                       return false;
+       }
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+       unsigned i, j, len;
+       FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+       FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+       if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+               return false;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+       pack_uint64_(block->lead_in, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+       len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+       memset(buffer, 0, len);
+       if(block->is_cd)
+               buffer[0] |= 0x80;
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+       len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+       pack_uint32_(block->num_tracks, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       for(i = 0; i < block->num_tracks; i++) {
+               FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+               pack_uint64_(track->offset, buffer, len);
+               if(write_cb(buffer, 1, len, handle) != len)
+                       return false;
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+               pack_uint32_(track->number, buffer, len);
+               if(write_cb(buffer, 1, len, handle) != len)
+                       return false;
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+               if(write_cb(track->isrc, 1, len, handle) != len)
+                       return false;
+
+               FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+               len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+               memset(buffer, 0, len);
+               buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
+               if(write_cb(buffer, 1, len, handle) != len)
+                       return false;
+
+               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+               len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+               pack_uint32_(track->num_indices, buffer, len);
+               if(write_cb(buffer, 1, len, handle) != len)
+                       return false;
+
+               for(j = 0; j < track->num_indices; j++) {
+                       FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+                       len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+                       pack_uint64_(index->offset, buffer, len);
+                       if(write_cb(buffer, 1, len, handle) != len)
+                               return false;
+
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+                       len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+                       pack_uint32_(index->number, buffer, len);
+                       if(write_cb(buffer, 1, len, handle) != len)
+                               return false;
+
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+                       len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+                       memset(buffer, 0, len);
+                       if(write_cb(buffer, 1, len, handle) != len)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+       unsigned len;
+       size_t slen;
+       FLAC__byte buffer[4]; /* magic number is asserted below */
+
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8);
+       FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+       FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8);
+
+       len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+       pack_uint32_(block->type, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+       slen = strlen(block->mime_type);
+       pack_uint32_(slen, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+       if(write_cb(block->mime_type, 1, slen, handle) != slen)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+       slen = strlen((const char *)block->description);
+       pack_uint32_(slen, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+       if(write_cb(block->description, 1, slen, handle) != slen)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+       pack_uint32_(block->width, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+       pack_uint32_(block->height, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+       pack_uint32_(block->depth, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
+       pack_uint32_(block->colors, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+
+       len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+       pack_uint32_(block->data_length, buffer, len);
+       if(write_cb(buffer, 1, len, handle) != len)
+               return false;
+       if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+       if(write_cb(block->data, 1, block_length, handle) != block_length)
+               return false;
+
+       return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+       if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+               return false;
+
+       if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+               return false;
+
+       if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
+{
+       FLAC__StreamMetadata *padding;
+
+       if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       block->is_last = false;
+
+       if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+               return false;
+
+       if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+               return false;
+
+       if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+               return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+       padding->is_last = padding_is_last;
+       padding->length = padding_length;
+
+       if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+               FLAC__metadata_object_delete(padding);
+               return false;
+       }
+
+       if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+               FLAC__metadata_object_delete(padding);
+               return false;
+       }
+
+       FLAC__metadata_object_delete(padding);
+
+       if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+       FILE *tempfile;
+       char *tempfilename;
+       int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+       off_t fixup_is_last_flag_offset = -1;
+
+       FLAC__ASSERT(0 != block || append == false);
+
+       if(iterator->is_last) {
+               if(append) {
+                       fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+                       fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+               }
+               else if(0 == block) {
+                       simple_iterator_push_(iterator);
+                       if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+                               (void)simple_iterator_pop_(iterator);
+                               return false;
+                       }
+                       fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+                       fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+                       if(!simple_iterator_pop_(iterator))
+                               return false;
+               }
+       }
+
+       if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+               return false;
+
+       if(0 != block) {
+               if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+                       cleanup_tempfile_(&tempfile, &tempfilename);
+                       return false;
+               }
+
+               if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+                       cleanup_tempfile_(&tempfile, &tempfilename);
+                       return false;
+               }
+       }
+
+       if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+               return false;
+
+       if(append)
+               return FLAC__metadata_simple_iterator_next(iterator);
+
+       return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
+       iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+       iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+       FLAC__ASSERT(iterator->depth > 0);
+       iterator->depth--;
+       if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+
+       return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+       FLAC__byte buffer[4];
+       size_t n;
+       unsigned i;
+
+       FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
+
+       /* skip any id3v2 tag */
+       errno = 0;
+       n = read_cb(buffer, 1, 4, handle);
+       if(errno)
+               return 1;
+       else if(n != 4)
+               return 3;
+       else if(0 == memcmp(buffer, "ID3", 3)) {
+               unsigned tag_length = 0;
+
+               /* skip to the tag length */
+               if(seek_cb(handle, 2, SEEK_CUR) < 0)
+                       return 2;
+
+               /* read the length */
+               for(i = 0; i < 4; i++) {
+                       if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+                               return 1;
+                       tag_length <<= 7;
+                       tag_length |= (buffer[0] & 0x7f);
+               }
+
+               /* skip the rest of the tag */
+               if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+                       return 2;
+
+               /* read the stream sync code */
+               errno = 0;
+               n = read_cb(buffer, 1, 4, handle);
+               if(errno)
+                       return 1;
+               else if(n != 4)
+                       return 3;
+       }
+
+       /* check for the fLaC signature */
+       if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+               return 0;
+       else
+               return 3;
+}
+
+unsigned seek_to_first_metadata_block_(FILE *f)
+{
+       return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+       const off_t offset_end = append? iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length : iterator->offset[iterator->depth];
+
+       if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+       if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+       if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+       off_t save_offset = iterator->offset[iterator->depth];
+       FLAC__ASSERT(0 != *tempfile);
+
+       if(0 != fseeko(iterator->file, save_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length, SEEK_SET)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+               return false;
+       }
+       if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+
+       if(fixup_is_last_code != 0) {
+               /*
+                * if code == 1, it means a block was appended to the end so
+                *   we have to clear the is_last flag of the previous block
+                * if code == -1, it means the last block was deleted so
+                *   we have to set the is_last flag of the previous block
+                */
+               /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+               FLAC__byte x;
+               if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+                       cleanup_tempfile_(tempfile, tempfilename);
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+                       return false;
+               }
+               if(fread(&x, 1, 1, *tempfile) != 1) {
+                       cleanup_tempfile_(tempfile, tempfilename);
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               }
+               if(fixup_is_last_code > 0) {
+                       FLAC__ASSERT(x & 0x80);
+                       x &= 0x7f;
+               }
+               else {
+                       FLAC__ASSERT(!(x & 0x80));
+                       x |= 0x80;
+               }
+               if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+                       cleanup_tempfile_(tempfile, tempfilename);
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+                       return false;
+               }
+               if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+                       cleanup_tempfile_(tempfile, tempfilename);
+                       iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+                       return false;
+               }
+       }
+
+       (void)fclose(iterator->file);
+
+       if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+               return false;
+
+       if(iterator->has_stats)
+               set_file_stats_(iterator->filename, &iterator->stats);
+
+       if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+               return false;
+       if(backup) {
+               while(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length < save_offset)
+                       if(!FLAC__metadata_simple_iterator_next(iterator))
+                               return false;
+               return true;
+       }
+       else {
+               /* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+               FLAC__ASSERT(iterator->depth == 0);
+               iterator->offset[0] = save_offset;
+               iterator->depth++;
+               return simple_iterator_pop_(iterator);
+       }
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       FLAC__byte buffer[8192];
+       size_t n;
+
+       FLAC__ASSERT(bytes >= 0);
+       while(bytes > 0) {
+               n = min(sizeof(buffer), (size_t)bytes);
+               if(fread(buffer, 1, n, file) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               }
+               if(local__fwrite(buffer, 1, n, tempfile) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+                       return false;
+               }
+               bytes -= n;
+       }
+
+       return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       FLAC__byte buffer[8192];
+       size_t n;
+
+       FLAC__ASSERT(bytes >= 0);
+       while(bytes > 0) {
+               n = min(sizeof(buffer), (size_t)bytes);
+               if(read_cb(buffer, 1, n, handle) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               }
+               if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+                       return false;
+               }
+               bytes -= n;
+       }
+
+       return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       FLAC__byte buffer[8192];
+       size_t n;
+
+       while(!feof(file)) {
+               n = fread(buffer, 1, sizeof(buffer), file);
+               if(n == 0 && !feof(file)) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               }
+               if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       FLAC__byte buffer[8192];
+       size_t n;
+
+       while(!eof_cb(handle)) {
+               n = read_cb(buffer, 1, sizeof(buffer), handle);
+               if(n == 0 && !eof_cb(handle)) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+                       return false;
+               }
+               if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       static const char *tempfile_suffix = ".metadata_edit";
+       if(0 == tempfile_path_prefix) {
+               if(0 == (*tempfilename = (char*)safe_malloc_add_3op_(strlen(filename), /*+*/strlen(tempfile_suffix), /*+*/1))) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               strcpy(*tempfilename, filename);
+               strcat(*tempfilename, tempfile_suffix);
+       }
+       else {
+               const char *p = strrchr(filename, '/');
+               if(0 == p)
+                       p = filename;
+               else
+                       p++;
+
+               if(0 == (*tempfilename = (char*)safe_malloc_add_4op_(strlen(tempfile_path_prefix), /*+*/strlen(p), /*+*/strlen(tempfile_suffix), /*+*/2))) {
+                       *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               strcpy(*tempfilename, tempfile_path_prefix);
+               strcat(*tempfilename, "/");
+               strcat(*tempfilename, p);
+               strcat(*tempfilename, tempfile_suffix);
+       }
+
+       if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != tempfile);
+       FLAC__ASSERT(0 != *tempfile);
+       FLAC__ASSERT(0 != tempfilename);
+       FLAC__ASSERT(0 != *tempfilename);
+       FLAC__ASSERT(0 != status);
+
+       (void)fclose(*tempfile);
+       *tempfile = 0;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+       /* on some flavors of windows, rename() will fail if the destination already exists */
+       if(unlink(filename) < 0) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
+               return false;
+       }
+#endif
+
+       /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */
+       if(0 != rename(*tempfilename, filename)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
+               return false;
+       }
+
+       cleanup_tempfile_(tempfile, tempfilename);
+
+       return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+       if(0 != *tempfile) {
+               (void)fclose(*tempfile);
+               *tempfile = 0;
+       }
+
+       if(0 != *tempfilename) {
+               (void)unlink(*tempfilename);
+               free(*tempfilename);
+               *tempfilename = 0;
+       }
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+       return (0 == stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct stat *stats)
+{
+       struct utimbuf srctime;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+
+       srctime.actime = stats->st_atime;
+       srctime.modtime = stats->st_mtime;
+       (void)chmod(filename, stats->st_mode);
+       (void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ && !defined __EMX__
+       (void)chown(filename, stats->st_uid, -1);
+       (void)chown(filename, -1, stats->st_gid);
+#endif
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+       return fseeko((FILE*)handle, (off_t)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+       return ftello((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+       switch(status) {
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+                       return FLAC__METADATA_CHAIN_STATUS_OK;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+                       return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+                       return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+                       return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+                       return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+                       return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+                       return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+               case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+               default:
+                       return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+       }
+}
diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c
new file mode 100644 (file)
index 0000000..a1465f5
--- /dev/null
@@ -0,0 +1,1819 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+
+
+/****************************************************************************
+ *
+ * Local routines
+ *
+ ***************************************************************************/
+
+/* copy bytes:
+ *  from = NULL  && bytes = 0
+ *       to <- NULL
+ *  from != NULL && bytes > 0
+ *       to <- copy of from
+ *  else ASSERT
+ * malloc error leaves 'to' unchanged
+ */
+static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+       FLAC__ASSERT(0 != to);
+       if(bytes > 0 && 0 != from) {
+               FLAC__byte *x;
+               if(0 == (x = (FLAC__byte*)safe_malloc_(bytes)))
+                       return false;
+               memcpy(x, from, bytes);
+               *to = x;
+       }
+       else {
+               FLAC__ASSERT(0 == from);
+               FLAC__ASSERT(bytes == 0);
+               *to = 0;
+       }
+       return true;
+}
+
+#if 0 /* UNUSED */
+/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */
+static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+       FLAC__byte *copy;
+       FLAC__ASSERT(0 != to);
+       if(copy_bytes_(&copy, from, bytes)) {
+               if(*to)
+                       free(*to);
+               *to = copy;
+               return true;
+       }
+       else
+               return false;
+}
+#endif
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
+{
+       FLAC__byte *x = (FLAC__byte*)safe_realloc_add_2op_(*entry, length, /*+*/1);
+       if(0 != x) {
+               x[length] = '\0';
+               *entry = x;
+               return true;
+       }
+       else
+               return false;
+}
+
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+       char *copy = strdup(from);
+       FLAC__ASSERT(to);
+       if(copy) {
+               if(*to)
+                       free(*to);
+               *to = copy;
+               return true;
+       }
+       else
+               return false;
+}
+
+static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
+{
+       to->length = from->length;
+       if(0 == from->entry) {
+               FLAC__ASSERT(from->length == 0);
+               to->entry = 0;
+       }
+       else {
+               FLAC__byte *x;
+               FLAC__ASSERT(from->length > 0);
+               if(0 == (x = (FLAC__byte*)safe_malloc_add_2op_(from->length, /*+*/1)))
+                       return false;
+               memcpy(x, from->entry, from->length);
+               x[from->length] = '\0';
+               to->entry = x;
+       }
+       return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+       memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+       if(0 == from->indices) {
+               FLAC__ASSERT(from->num_indices == 0);
+       }
+       else {
+               FLAC__StreamMetadata_CueSheet_Index *x;
+               FLAC__ASSERT(from->num_indices > 0);
+               if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)safe_malloc_mul_2op_(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+                       return false;
+               memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+               to->indices = x;
+       }
+       return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
+{
+       FLAC__StreamMetadata_SeekPoint *object_array;
+
+       FLAC__ASSERT(num_points > 0);
+
+       object_array = (FLAC__StreamMetadata_SeekPoint*)safe_malloc_mul_2op_(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
+
+       if(0 != object_array) {
+               unsigned i;
+               for(i = 0; i < num_points; i++) {
+                       object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+                       object_array[i].stream_offset = 0;
+                       object_array[i].frame_samples = 0;
+               }
+       }
+
+       return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+       unsigned i;
+
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+       object->length += object->data.vorbis_comment.vendor_string.length;
+       object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+       for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+               object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+               object->length += object->data.vorbis_comment.comments[i].length;
+       }
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
+{
+       FLAC__ASSERT(num_comments > 0);
+
+       return (FLAC__StreamMetadata_VorbisComment_Entry*)safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != object_array && num_comments > 0);
+
+       for(i = 0; i < num_comments; i++)
+               if(0 != object_array[i].entry)
+                       free(object_array[i].entry);
+
+       if(0 != object_array)
+               free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+       FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+       FLAC__ASSERT(0 != object_array);
+       FLAC__ASSERT(num_comments > 0);
+
+       return_array = vorbiscomment_entry_array_new_(num_comments);
+
+       if(0 != return_array) {
+               unsigned i;
+
+               for(i = 0; i < num_comments; i++) {
+                       if(!copy_vcentry_(return_array+i, object_array+i)) {
+                               vorbiscomment_entry_array_delete_(return_array, num_comments);
+                               return 0;
+                       }
+               }
+       }
+
+       return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+       FLAC__byte *save;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(0 != dest);
+       FLAC__ASSERT(0 != src);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0));
+
+       save = dest->entry;
+
+       if(0 != src->entry && src->length > 0) {
+               if(copy) {
+                       /* do the copy first so that if we fail we leave the dest object untouched */
+                       if(!copy_vcentry_(dest, src))
+                               return false;
+               }
+               else {
+                       /* we have to make sure that the string we're taking over is null-terminated */
+
+                       /*
+                        * Stripping the const from src->entry is OK since we're taking
+                        * ownership of the pointer.  This is a hack around a deficiency
+                        * in the API where the same function is used for 'copy' and
+                        * 'own', but the source entry is a const pointer.  If we were
+                        * precise, the 'own' flavor would be a separate function with a
+                        * non-const source pointer.  But it's not, so we hack away.
+                        */
+                       if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+                               return false;
+                       *dest = *src;
+               }
+       }
+       else {
+               /* the src is null */
+               *dest = *src;
+       }
+
+       if(0 != save)
+               free(save);
+
+       vorbiscomment_calculate_length_(object);
+       return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != field_name);
+
+       for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+               if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
+                       return (int)i;
+       }
+
+       return -1;
+}
+
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+       unsigned i;
+
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       object->length = (
+               FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+       ) / 8;
+
+       object->length += object->data.cue_sheet.num_tracks * (
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+       ) / 8;
+
+       for(i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+               object->length += object->data.cue_sheet.tracks[i].num_indices * (
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+               ) / 8;
+       }
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
+{
+       FLAC__ASSERT(num_indices > 0);
+
+       return (FLAC__StreamMetadata_CueSheet_Index*)safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
+{
+       FLAC__ASSERT(num_tracks > 0);
+
+       return (FLAC__StreamMetadata_CueSheet_Track*)safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != object_array && num_tracks > 0);
+
+       for(i = 0; i < num_tracks; i++) {
+               if(0 != object_array[i].indices) {
+                       FLAC__ASSERT(object_array[i].num_indices > 0);
+                       free(object_array[i].indices);
+               }
+       }
+
+       if(0 != object_array)
+               free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+       FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+       FLAC__ASSERT(0 != object_array);
+       FLAC__ASSERT(num_tracks > 0);
+
+       return_array = cuesheet_track_array_new_(num_tracks);
+
+       if(0 != return_array) {
+               unsigned i;
+
+               for(i = 0; i < num_tracks; i++) {
+                       if(!copy_track_(return_array+i, object_array+i)) {
+                               cuesheet_track_array_delete_(return_array, num_tracks);
+                               return 0;
+                       }
+               }
+       }
+
+       return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+       FLAC__StreamMetadata_CueSheet_Index *save;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(0 != dest);
+       FLAC__ASSERT(0 != src);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));
+
+       save = dest->indices;
+
+       /* do the copy first so that if we fail we leave the object untouched */
+       if(copy) {
+               if(!copy_track_(dest, src))
+                       return false;
+       }
+       else {
+               *dest = *src;
+       }
+
+       if(0 != save)
+               free(save);
+
+       cuesheet_calculate_length_(object);
+       return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+       FLAC__StreamMetadata *object;
+
+       if(type > FLAC__MAX_METADATA_TYPE_CODE)
+               return 0;
+
+       object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata));
+       if(0 != object) {
+               object->is_last = false;
+               object->type = type;
+               switch(type) {
+                       case FLAC__METADATA_TYPE_STREAMINFO:
+                               object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+                               break;
+                       case FLAC__METADATA_TYPE_PADDING:
+                               /* calloc() took care of this for us:
+                               object->length = 0;
+                               */
+                               break;
+                       case FLAC__METADATA_TYPE_APPLICATION:
+                               object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+                               /* calloc() took care of this for us:
+                               object->data.application.data = 0;
+                               */
+                               break;
+                       case FLAC__METADATA_TYPE_SEEKTABLE:
+                               /* calloc() took care of this for us:
+                               object->length = 0;
+                               object->data.seek_table.num_points = 0;
+                               object->data.seek_table.points = 0;
+                               */
+                               break;
+                       case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                               object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
+                               if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
+                                       free(object);
+                                       return 0;
+                               }
+                               vorbiscomment_calculate_length_(object);
+                               break;
+                       case FLAC__METADATA_TYPE_CUESHEET:
+                               cuesheet_calculate_length_(object);
+                               break;
+                       case FLAC__METADATA_TYPE_PICTURE:
+                               object->length = (
+                                       FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+                                       FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+                                       FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+                                       FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+                                       FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+                                       FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+                                       FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+                                       FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+                                       0 /* no data */
+                               ) / 8;
+                               object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+                               object->data.picture.mime_type = 0;
+                               object->data.picture.description = 0;
+                               /* calloc() took care of this for us:
+                               object->data.picture.width = 0;
+                               object->data.picture.height = 0;
+                               object->data.picture.depth = 0;
+                               object->data.picture.colors = 0;
+                               object->data.picture.data_length = 0;
+                               object->data.picture.data = 0;
+                               */
+                               /* now initialize mime_type and description with empty strings to make things easier on the client */
+                               if(!copy_cstring_(&object->data.picture.mime_type, "")) {
+                                       free(object);
+                                       return 0;
+                               }
+                               if(!copy_cstring_((char**)(&object->data.picture.description), "")) {
+                                       if(object->data.picture.mime_type)
+                                               free(object->data.picture.mime_type);
+                                       free(object);
+                                       return 0;
+                               }
+                               break;
+                       default:
+                               /* calloc() took care of this for us:
+                               object->length = 0;
+                               object->data.unknown.data = 0;
+                               */
+                               break;
+               }
+       }
+
+       return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+       FLAC__StreamMetadata *to;
+
+       FLAC__ASSERT(0 != object);
+
+       if(0 != (to = FLAC__metadata_object_new(object->type))) {
+               to->is_last = object->is_last;
+               to->type = object->type;
+               to->length = object->length;
+               switch(to->type) {
+                       case FLAC__METADATA_TYPE_STREAMINFO:
+                               memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+                               break;
+                       case FLAC__METADATA_TYPE_PADDING:
+                               break;
+                       case FLAC__METADATA_TYPE_APPLICATION:
+                               if(to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
+                               if(!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               break;
+                       case FLAC__METADATA_TYPE_SEEKTABLE:
+                               to->data.seek_table.num_points = object->data.seek_table.num_points;
+                               if(to->data.seek_table.num_points > SIZE_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               if(!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               break;
+                       case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                               if(0 != to->data.vorbis_comment.vendor_string.entry) {
+                                       free(to->data.vorbis_comment.vendor_string.entry);
+                                       to->data.vorbis_comment.vendor_string.entry = 0;
+                               }
+                               if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               if(object->data.vorbis_comment.num_comments == 0) {
+                                       FLAC__ASSERT(0 == object->data.vorbis_comment.comments);
+                                       to->data.vorbis_comment.comments = 0;
+                               }
+                               else {
+                                       FLAC__ASSERT(0 != object->data.vorbis_comment.comments);
+                                       to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+                                       if(0 == to->data.vorbis_comment.comments) {
+                                               FLAC__metadata_object_delete(to);
+                                               return 0;
+                                       }
+                               }
+                               to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+                               break;
+                       case FLAC__METADATA_TYPE_CUESHEET:
+                               memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+                               if(object->data.cue_sheet.num_tracks == 0) {
+                                       FLAC__ASSERT(0 == object->data.cue_sheet.tracks);
+                               }
+                               else {
+                                       FLAC__ASSERT(0 != object->data.cue_sheet.tracks);
+                                       to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+                                       if(0 == to->data.cue_sheet.tracks) {
+                                               FLAC__metadata_object_delete(to);
+                                               return 0;
+                                       }
+                               }
+                               break;
+                       case FLAC__METADATA_TYPE_PICTURE:
+                               to->data.picture.type = object->data.picture.type;
+                               if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               to->data.picture.width = object->data.picture.width;
+                               to->data.picture.height = object->data.picture.height;
+                               to->data.picture.depth = object->data.picture.depth;
+                               to->data.picture.colors = object->data.picture.colors;
+                               to->data.picture.data_length = object->data.picture.data_length;
+                               if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               break;
+                       default:
+                               if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
+                                       FLAC__metadata_object_delete(to);
+                                       return 0;
+                               }
+                               break;
+               }
+       }
+
+       return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+       FLAC__ASSERT(0 != object);
+
+       switch(object->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+               case FLAC__METADATA_TYPE_PADDING:
+                       break;
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       if(0 != object->data.application.data) {
+                               free(object->data.application.data);
+                               object->data.application.data = 0;
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       if(0 != object->data.seek_table.points) {
+                               free(object->data.seek_table.points);
+                               object->data.seek_table.points = 0;
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       if(0 != object->data.vorbis_comment.vendor_string.entry) {
+                               free(object->data.vorbis_comment.vendor_string.entry);
+                               object->data.vorbis_comment.vendor_string.entry = 0;
+                       }
+                       if(0 != object->data.vorbis_comment.comments) {
+                               FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+                               vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       if(0 != object->data.cue_sheet.tracks) {
+                               FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+                               cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_PICTURE:
+                       if(0 != object->data.picture.mime_type) {
+                               free(object->data.picture.mime_type);
+                               object->data.picture.mime_type = 0;
+                       }
+                       if(0 != object->data.picture.description) {
+                               free(object->data.picture.description);
+                               object->data.picture.description = 0;
+                       }
+                       if(0 != object->data.picture.data) {
+                               free(object->data.picture.data);
+                               object->data.picture.data = 0;
+                       }
+                       break;
+               default:
+                       if(0 != object->data.unknown.data) {
+                               free(object->data.unknown.data);
+                               object->data.unknown.data = 0;
+                       }
+                       break;
+       }
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+       FLAC__metadata_object_delete_data(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;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+       unsigned i, j;
+
+       if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number))
+               return false;
+
+       if(block1->lead_in != block2->lead_in)
+               return false;
+
+       if(block1->is_cd != block2->is_cd)
+               return false;
+
+       if(block1->num_tracks != block2->num_tracks)
+               return false;
+
+       if(0 != block1->tracks && 0 != block2->tracks) {
+               FLAC__ASSERT(block1->num_tracks > 0);
+               for(i = 0; i < block1->num_tracks; i++) {
+                       if(block1->tracks[i].offset != block2->tracks[i].offset)
+                               return false;
+                       if(block1->tracks[i].number != block2->tracks[i].number)
+                               return false;
+                       if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)))
+                               return false;
+                       if(block1->tracks[i].type != block2->tracks[i].type)
+                               return false;
+                       if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+                               return false;
+                       if(block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+                               return false;
+                       if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) {
+                               FLAC__ASSERT(block1->tracks[i].num_indices > 0);
+                               for(j = 0; j < block1->tracks[i].num_indices; j++) {
+                                       if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+                                               return false;
+                                       if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+                                               return false;
+                               }
+                       }
+                       else if(block1->tracks[i].indices != block2->tracks[i].indices)
+                               return false;
+               }
+       }
+       else if(block1->tracks != block2->tracks)
+               return false;
+       return true;
+}
+
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+       if(block1->type != block2->type)
+               return false;
+       if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type)))
+               return false;
+       if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description)))
+               return false;
+       if(block1->width != block2->width)
+               return false;
+       if(block1->height != block2->height)
+               return false;
+       if(block1->depth != block2->depth)
+               return false;
+       if(block1->colors != block2->colors)
+               return false;
+       if(block1->data_length != block2->data_length)
+               return false;
+       if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length)))
+               return false;
+       return true;
+}
+
+static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
+{
+       FLAC__ASSERT(0 != block1);
+       FLAC__ASSERT(0 != block2);
+
+       if(0 != block1->data && 0 != block2->data)
+               return 0 == memcmp(block1->data, block2->data, block_length);
+       else
+               return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+       FLAC__ASSERT(0 != block1);
+       FLAC__ASSERT(0 != 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);
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+               case FLAC__METADATA_TYPE_PICTURE:
+                       return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
+               default:
+                       return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
+{
+       FLAC__byte *save;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
+       FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+       save = object->data.application.data;
+
+       /* do the copy first so that if we fail we leave the object untouched */
+       if(copy) {
+               if(!copy_bytes_(&object->data.application.data, data, length))
+                       return false;
+       }
+       else {
+               object->data.application.data = data;
+       }
+
+       if(0 != save)
+               free(save);
+
+       object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       if(0 == object->data.seek_table.points) {
+               FLAC__ASSERT(object->data.seek_table.num_points == 0);
+               if(0 == new_num_points)
+                       return true;
+               else if(0 == (object->data.seek_table.points = seekpoint_array_new_(new_num_points)))
+                       return false;
+       }
+       else {
+               const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+               const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+
+               /* overflow check */
+               if((size_t)new_num_points > SIZE_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
+                       return false;
+
+               FLAC__ASSERT(object->data.seek_table.num_points > 0);
+
+               if(new_size == 0) {
+                       free(object->data.seek_table.points);
+                       object->data.seek_table.points = 0;
+               }
+               else if(0 == (object->data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(object->data.seek_table.points, new_size)))
+                       return false;
+
+               /* if growing, set new elements to placeholders */
+               if(new_size > old_size) {
+                       unsigned i;
+                       for(i = object->data.seek_table.num_points; i < new_num_points; i++) {
+                               object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+                               object->data.seek_table.points[i].stream_offset = 0;
+                               object->data.seek_table.points[i].frame_samples = 0;
+                       }
+               }
+       }
+
+       object->data.seek_table.num_points = new_num_points;
+
+       seektable_calculate_length_(object);
+       return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+       object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+       int i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
+
+       if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+               return false;
+
+       /* move all points >= point_num forward one space */
+       for(i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+               object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+       FLAC__metadata_object_seektable_set_point(object, point_num, point);
+       seektable_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+       /* move all points > point_num backward one space */
+       for(i = point_num; i < object->data.seek_table.num_points-1; i++)
+               object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+       return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       if(num > 0)
+               /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+               return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+       else
+               return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+       FLAC__StreamMetadata_SeekTable *seek_table;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       seek_table = &object->data.seek_table;
+
+       if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+               return false;
+
+       seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+       seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+       seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(0 != sample_numbers || num == 0);
+
+       if(num > 0) {
+               FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+               unsigned i, j;
+
+               i = seek_table->num_points;
+
+               if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+                       return false;
+
+               for(j = 0; j < num; i++, j++) {
+                       seek_table->points[i].sample_number = sample_numbers[j];
+                       seek_table->points[i].stream_offset = 0;
+                       seek_table->points[i].frame_samples = 0;
+               }
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(total_samples > 0);
+
+       if(num > 0 && total_samples > 0) {
+               FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+               unsigned i, j;
+
+               i = seek_table->num_points;
+
+               if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+                       return false;
+
+               for(j = 0; j < num; i++, j++) {
+                       seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+                       seek_table->points[i].stream_offset = 0;
+                       seek_table->points[i].frame_samples = 0;
+               }
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+       FLAC__ASSERT(samples > 0);
+       FLAC__ASSERT(total_samples > 0);
+
+       if(samples > 0 && total_samples > 0) {
+               FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+               unsigned i, j;
+               FLAC__uint64 num, sample;
+
+               num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
+               /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
+               if(total_samples % samples == 0)
+                       num--;
+
+               i = seek_table->num_points;
+
+               if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num))
+                       return false;
+
+               sample = 0;
+               for(j = 0; j < num; i++, j++, sample += samples) {
+                       seek_table->points[i].sample_number = sample;
+                       seek_table->points[i].stream_offset = 0;
+                       seek_table->points[i].frame_samples = 0;
+               }
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
+{
+       unsigned unique;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+       return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+       if(!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
+               return false;
+       return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       if(0 == object->data.vorbis_comment.comments) {
+               FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
+               if(0 == new_num_comments)
+                       return true;
+               else if(0 == (object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)))
+                       return false;
+       }
+       else {
+               const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+               const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+
+               /* overflow check */
+               if((size_t)new_num_comments > SIZE_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
+                       return false;
+
+               FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+
+               /* if shrinking, free the truncated entries */
+               if(new_num_comments < object->data.vorbis_comment.num_comments) {
+                       unsigned i;
+                       for(i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+                               if(0 != object->data.vorbis_comment.comments[i].entry)
+                                       free(object->data.vorbis_comment.comments[i].entry);
+               }
+
+               if(new_size == 0) {
+                       free(object->data.vorbis_comment.comments);
+                       object->data.vorbis_comment.comments = 0;
+               }
+               else if(0 == (object->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(object->data.vorbis_comment.comments, new_size)))
+                       return false;
+
+               /* if growing, zero all the length/pointers of new elements */
+               if(new_size > old_size)
+                       memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+       }
+
+       object->data.vorbis_comment.num_comments = new_num_comments;
+
+       vorbiscomment_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+       if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+               return false;
+       return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+       FLAC__StreamMetadata_VorbisComment *vc;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
+
+       if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+               return false;
+
+       vc = &object->data.vorbis_comment;
+
+       if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
+               return false;
+
+       /* move all comments >= comment_num forward one space */
+       memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+       vc->comments[comment_num].length = 0;
+       vc->comments[comment_num].entry = 0;
+
+       return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+       FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+
+       if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+               return false;
+
+       {
+               int i;
+               size_t field_name_length;
+               const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+               FLAC__ASSERT(0 != eq);
+
+               if(0 == eq)
+                       return false; /* double protection */
+
+               field_name_length = eq-entry.entry;
+
+               if((i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length)) >= 0) {
+                       unsigned index = (unsigned)i;
+                       if(!FLAC__metadata_object_vorbiscomment_set_comment(object, index, entry, copy))
+                               return false;
+                       if(all && (index+1 < object->data.vorbis_comment.num_comments)) {
+                               for(i = vorbiscomment_find_entry_from_(object, index+1, (const char *)entry.entry, field_name_length); i >= 0; ) {
+                                       if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i))
+                                               return false;
+                                       if((unsigned)i < object->data.vorbis_comment.num_comments)
+                                               i = vorbiscomment_find_entry_from_(object, (unsigned)i, (const char *)entry.entry, field_name_length);
+                                       else
+                                               i = -1;
+                               }
+                       }
+                       return true;
+               }
+               else
+                       return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
+{
+       FLAC__StreamMetadata_VorbisComment *vc;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+       vc = &object->data.vorbis_comment;
+
+       /* free the comment at comment_num */
+       if(0 != vc->comments[comment_num].entry)
+               free(vc->comments[comment_num].entry);
+
+       /* move all comments > comment_num backward one space */
+       memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+       vc->comments[vc->num_comments-1].length = 0;
+       vc->comments[vc->num_comments-1].entry = 0;
+
+       return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
+{
+       FLAC__ASSERT(0 != entry);
+       FLAC__ASSERT(0 != field_name);
+       FLAC__ASSERT(0 != field_value);
+
+       if(!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+               return false;
+       if(!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1)))
+               return false;
+
+       {
+               const size_t nn = strlen(field_name);
+               const size_t nv = strlen(field_value);
+               entry->length = nn + 1 /*=*/ + nv;
+               if(0 == (entry->entry = (FLAC__byte*)safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)))
+                       return false;
+               memcpy(entry->entry, field_name, nn);
+               entry->entry[nn] = '=';
+               memcpy(entry->entry+nn+1, field_value, nv);
+               entry->entry[entry->length] = '\0';
+       }
+       
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+       FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+       FLAC__ASSERT(0 != field_name);
+       FLAC__ASSERT(0 != field_value);
+
+       if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+               return false;
+
+       {
+               const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+               const size_t nn = eq-entry.entry;
+               const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+               FLAC__ASSERT(0 != eq);
+               if(0 == eq)
+                       return false; /* double protection */
+               if(0 == (*field_name = (char*)safe_malloc_add_2op_(nn, /*+*/1)))
+                       return false;
+               if(0 == (*field_value = (char*)safe_malloc_add_2op_(nv, /*+*/1))) {
+                       free(*field_name);
+                       return false;
+               }
+               memcpy(*field_name, entry.entry, nn);
+               memcpy(*field_value, entry.entry+nn+1, nv);
+               (*field_name)[nn] = '\0';
+               (*field_value)[nv] = '\0';
+       }
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
+{
+       FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+       {
+               const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+               return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length));
+#undef FLAC__STRNCASECMP
+       }
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+{
+       FLAC__ASSERT(0 != field_name);
+
+       return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+       const unsigned field_name_length = strlen(field_name);
+       unsigned i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+               if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+                       if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+                               return -1;
+                       else
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+       FLAC__bool ok = true;
+       unsigned matching = 0;
+       const unsigned field_name_length = strlen(field_name);
+       int i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       /* must delete from end to start otherwise it will interfere with our iteration */
+       for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+               if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+                       matching++;
+                       ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
+               }
+       }
+
+       return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+       return (FLAC__StreamMetadata_CueSheet_Track*)calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
+{
+       FLAC__StreamMetadata_CueSheet_Track *to;
+
+       FLAC__ASSERT(0 != object);
+
+       if(0 != (to = FLAC__metadata_object_cuesheet_track_new())) {
+               if(!copy_track_(to, object)) {
+                       FLAC__metadata_object_cuesheet_track_delete(to);
+                       return 0;
+               }
+       }
+
+       return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+       FLAC__ASSERT(0 != object);
+
+       if(0 != object->indices) {
+               FLAC__ASSERT(object->num_indices > 0);
+               free(object->indices);
+       }
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+       FLAC__metadata_object_cuesheet_track_delete_data(object);
+       free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
+{
+       FLAC__StreamMetadata_CueSheet_Track *track;
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+       track = &object->data.cue_sheet.tracks[track_num];
+
+       if(0 == track->indices) {
+               FLAC__ASSERT(track->num_indices == 0);
+               if(0 == new_num_indices)
+                       return true;
+               else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices)))
+                       return false;
+       }
+       else {
+               const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+               const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+               /* overflow check */
+               if((size_t)new_num_indices > SIZE_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
+                       return false;
+
+               FLAC__ASSERT(track->num_indices > 0);
+
+               if(new_size == 0) {
+                       free(track->indices);
+                       track->indices = 0;
+               }
+               else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size)))
+                       return false;
+
+               /* if growing, zero all the lengths/pointers of new elements */
+               if(new_size > old_size)
+                       memset(track->indices + track->num_indices, 0, new_size - old_size);
+       }
+
+       track->num_indices = new_num_indices;
+
+       cuesheet_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index)
+{
+       FLAC__StreamMetadata_CueSheet_Track *track;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+       FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
+
+       track = &object->data.cue_sheet.tracks[track_num];
+
+       if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+               return false;
+
+       /* move all indices >= index_num forward one space */
+       memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+       track->indices[index_num] = index;
+       cuesheet_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+       FLAC__StreamMetadata_CueSheet_Index index;
+       memset(&index, 0, sizeof(index));
+       return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, index);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+       FLAC__StreamMetadata_CueSheet_Track *track;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+       FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
+
+       track = &object->data.cue_sheet.tracks[track_num];
+
+       /* move all indices > index_num backward one space */
+       memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+       FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+       cuesheet_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       if(0 == object->data.cue_sheet.tracks) {
+               FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+               if(0 == new_num_tracks)
+                       return true;
+               else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)))
+                       return false;
+       }
+       else {
+               const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+               const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+               /* overflow check */
+               if((size_t)new_num_tracks > SIZE_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
+                       return false;
+
+               FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+
+               /* if shrinking, free the truncated entries */
+               if(new_num_tracks < object->data.cue_sheet.num_tracks) {
+                       unsigned i;
+                       for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+                               if(0 != object->data.cue_sheet.tracks[i].indices)
+                                       free(object->data.cue_sheet.tracks[i].indices);
+               }
+
+               if(new_size == 0) {
+                       free(object->data.cue_sheet.tracks);
+                       object->data.cue_sheet.tracks = 0;
+               }
+               else if(0 == (object->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(object->data.cue_sheet.tracks, new_size)))
+                       return false;
+
+               /* if growing, zero all the lengths/pointers of new elements */
+               if(new_size > old_size)
+                       memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+       }
+
+       object->data.cue_sheet.num_tracks = new_num_tracks;
+
+       cuesheet_calculate_length_(object);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+       return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+       FLAC__StreamMetadata_CueSheet *cs;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
+
+       cs = &object->data.cue_sheet;
+
+       if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+               return false;
+
+       /* move all tracks >= track_num forward one space */
+       memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+       cs->tracks[track_num].num_indices = 0;
+       cs->tracks[track_num].indices = 0;
+
+       return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+       FLAC__StreamMetadata_CueSheet_Track track;
+       memset(&track, 0, sizeof(track));
+       return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+       FLAC__StreamMetadata_CueSheet *cs;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+       FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+       cs = &object->data.cue_sheet;
+
+       /* free the track at track_num */
+       if(0 != cs->tracks[track_num].indices)
+               free(cs->tracks[track_num].indices);
+
+       /* move all tracks > track_num backward one space */
+       memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+       cs->tracks[cs->num_tracks-1].num_indices = 0;
+       cs->tracks[cs->num_tracks-1].indices = 0;
+
+       return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
+{
+       if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+               return 0;
+       else if (cs->tracks[track].indices[0].number == 1)
+               return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+       else if (cs->tracks[track].num_indices < 2)
+               return 0;
+       else if (cs->tracks[track].indices[1].number == 1)
+               return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+       else
+               return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+       FLAC__uint32 n = 0;
+       while (x) {
+               n += (x%10);
+               x /= 10;
+       }
+       return n;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+       const FLAC__StreamMetadata_CueSheet *cs;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       cs = &object->data.cue_sheet;
+
+       if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+               return 0;
+
+       {
+               FLAC__uint32 i, length, sum = 0;
+               for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+                       sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+               length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+               return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+       }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
+{
+       char *old;
+       size_t old_length, new_length;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+       FLAC__ASSERT(0 != mime_type);
+
+       old = object->data.picture.mime_type;
+       old_length = old? strlen(old) : 0;
+       new_length = strlen(mime_type);
+
+       /* do the copy first so that if we fail we leave the object untouched */
+       if(copy) {
+               if(new_length >= SIZE_MAX) /* overflow check */
+                       return false;
+               if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
+                       return false;
+       }
+       else {
+               object->data.picture.mime_type = mime_type;
+       }
+
+       if(0 != old)
+               free(old);
+
+       object->length -= old_length;
+       object->length += new_length;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
+{
+       FLAC__byte *old;
+       size_t old_length, new_length;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+       FLAC__ASSERT(0 != description);
+
+       old = object->data.picture.description;
+       old_length = old? strlen((const char *)old) : 0;
+       new_length = strlen((const char *)description);
+
+       /* do the copy first so that if we fail we leave the object untouched */
+       if(copy) {
+               if(new_length >= SIZE_MAX) /* overflow check */
+                       return false;
+               if(!copy_bytes_(&object->data.picture.description, description, new_length+1))
+                       return false;
+       }
+       else {
+               object->data.picture.description = description;
+       }
+
+       if(0 != old)
+               free(old);
+
+       object->length -= old_length;
+       object->length += new_length;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+       FLAC__byte *old;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+       FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+       old = object->data.picture.data;
+
+       /* do the copy first so that if we fail we leave the object untouched */
+       if(copy) {
+               if(!copy_bytes_(&object->data.picture.data, data, length))
+                       return false;
+       }
+       else {
+               object->data.picture.data = data;
+       }
+
+       if(0 != old)
+               free(old);
+
+       object->length -= object->data.picture.data_length;
+       object->data.picture.data_length = length;
+       object->length += length;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+       return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
diff --git a/src/libFLAC/ogg_decoder_aspect.c b/src/libFLAC/ogg_decoder_aspect.c
new file mode 100644 (file)
index 0000000..6974de3
--- /dev/null
@@ -0,0 +1,253 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memcpy() */
+#include "FLAC/assert.h"
+#include "private/ogg_decoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
+{
+       /* we will determine the serial number later if necessary */
+       if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+               return false;
+
+       if(ogg_sync_init(&aspect->sync_state) != 0)
+               return false;
+
+       aspect->version_major = ~(0u);
+       aspect->version_minor = ~(0u);
+
+       aspect->need_serial_number = aspect->use_first_serial_number;
+
+       aspect->end_of_stream = false;
+       aspect->have_working_page = false;
+
+       return true;
+}
+
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
+{
+       (void)ogg_sync_clear(&aspect->sync_state);
+       (void)ogg_stream_clear(&aspect->stream_state);
+}
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
+{
+       aspect->use_first_serial_number = false;
+       aspect->serial_number = value;
+}
+
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
+{
+       aspect->use_first_serial_number = true;
+}
+
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
+{
+       (void)ogg_stream_reset(&aspect->stream_state);
+       (void)ogg_sync_reset(&aspect->sync_state);
+       aspect->end_of_stream = false;
+       aspect->have_working_page = false;
+}
+
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
+{
+       FLAC__ogg_decoder_aspect_flush(aspect);
+
+       if(aspect->use_first_serial_number)
+               aspect->need_serial_number = true;
+}
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
+{
+       static const size_t OGG_BYTES_CHUNK = 8192;
+       const size_t bytes_requested = *bytes;
+
+       /*
+        * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
+        * is push-based.  In libFLAC, when you ask to decode a frame, the
+        * decoder will eventually call the read callback to supply some data,
+        * but how much it asks for depends on how much free space it has in
+        * its internal buffer.  It does not try to grow its internal buffer
+        * to accomodate a whole frame because then the internal buffer size
+        * could not be limited, which is necessary in embedded applications.
+        *
+        * Ogg however grows its internal buffer until a whole page is present;
+        * only then can you get decoded data out.  So we can't just ask for
+        * the same number of bytes from Ogg, then pass what's decoded down to
+        * libFLAC.  If what libFLAC is asking for will not contain a whole
+        * page, then we will get no data from ogg_sync_pageout(), and at the
+        * same time cannot just read more data from the client for the purpose
+        * of getting a whole decoded page because the decoded size might be
+        * larger than libFLAC's internal buffer.
+        *
+        * Instead, whenever this read callback wrapper is called, we will
+        * continually request data from the client until we have at least one
+        * page, and manage pages internally so that we can send pieces of
+        * pages down to libFLAC in such a way that we obey its size
+        * requirement.  To limit the amount of callbacks, we will always try
+        * to read in enough pages to return the full number of bytes
+        * requested.
+        */
+       *bytes = 0;
+       while (*bytes < bytes_requested && !aspect->end_of_stream) {
+               if (aspect->have_working_page) {
+                       if (aspect->have_working_packet) {
+                               size_t n = bytes_requested - *bytes;
+                               if ((size_t)aspect->working_packet.bytes <= n) {
+                                       /* the rest of the packet will fit in the buffer */
+                                       n = aspect->working_packet.bytes;
+                                       memcpy(buffer, aspect->working_packet.packet, n);
+                                       *bytes += n;
+                                       buffer += n;
+                                       aspect->have_working_packet = false;
+                               }
+                               else {
+                                       /* only n bytes of the packet will fit in the buffer */
+                                       memcpy(buffer, aspect->working_packet.packet, n);
+                                       *bytes += n;
+                                       buffer += n;
+                                       aspect->working_packet.packet += n;
+                                       aspect->working_packet.bytes -= n;
+                               }
+                       }
+                       else {
+                               /* try and get another packet */
+                               const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
+                               if (ret > 0) {
+                                       aspect->have_working_packet = true;
+                                       /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
+                                       if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
+                                               const FLAC__byte *b = aspect->working_packet.packet;
+                                               const unsigned header_length =
+                                                       FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+                                                       FLAC__OGG_MAPPING_MAGIC_LENGTH +
+                                                       FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+                                                       FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+                                                       FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
+                                               if (aspect->working_packet.bytes < (long)header_length)
+                                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+                                               b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+                                               if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
+                                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+                                               b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+                                               aspect->version_major = (unsigned)(*b);
+                                               b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+                                               aspect->version_minor = (unsigned)(*b);
+                                               if (aspect->version_major != 1)
+                                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
+                                               aspect->working_packet.packet += header_length;
+                                               aspect->working_packet.bytes -= header_length;
+                                       }
+                               }
+                               else if (ret == 0) {
+                                       aspect->have_working_page = false;
+                               }
+                               else { /* ret < 0 */
+                                       /* lost sync, we'll leave the working page for the next call */
+                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+                               }
+                       }
+               }
+               else {
+                       /* try and get another page */
+                       const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
+                       if (ret > 0) {
+                               /* got a page, grab the serial number if necessary */
+                               if(aspect->need_serial_number) {
+                                       aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
+                                       aspect->need_serial_number = false;
+                               }
+                               if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
+                                       aspect->have_working_page = true;
+                                       aspect->have_working_packet = false;
+                               }
+                               /* else do nothing, could be a page from another stream */
+                       }
+                       else if (ret == 0) {
+                               /* need more data */
+                               const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
+                               char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
+
+                               if(0 == oggbuf) {
+                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
+                               }
+                               else {
+                                       size_t ogg_bytes_read = ogg_bytes_to_read;
+
+                                       switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
+                                               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+                                                       break;
+                                               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+                                                       aspect->end_of_stream = true;
+                                                       break;
+                                               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+                                                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+                                               default:
+                                                       FLAC__ASSERT(0);
+                                       }
+
+                                       if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
+                                               /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
+                                               FLAC__ASSERT(0);
+                                               return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
+                                       }
+                               }
+                       }
+                       else { /* ret < 0 */
+                               /* lost sync, bail out */
+                               return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+                       }
+               }
+       }
+
+       if (aspect->end_of_stream && *bytes == 0) {
+               return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+       }
+
+       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+}
diff --git a/src/libFLAC/ogg_encoder_aspect.c b/src/libFLAC/ogg_encoder_aspect.c
new file mode 100644 (file)
index 0000000..37df089
--- /dev/null
@@ -0,0 +1,227 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include "FLAC/assert.h"
+#include "private/ogg_encoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1;
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0;
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect)
+{
+       /* we will determine the serial number later if necessary */
+       if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+               return false;
+
+       aspect->seen_magic = false;
+       aspect->is_first_packet = true;
+       aspect->samples_written = 0;
+
+       return true;
+}
+
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect)
+{
+       (void)ogg_stream_clear(&aspect->stream_state);
+       /*@@@ what about the page? */
+}
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value)
+{
+       aspect->serial_number = value;
+}
+
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value)
+{
+       if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) {
+               aspect->num_metadata = value;
+               return true;
+       }
+       else
+               return false;
+}
+
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect)
+{
+       aspect->serial_number = 0;
+       aspect->num_metadata = 0;
+}
+
+/*
+ * The basic FLAC -> Ogg mapping goes like this:
+ *
+ * - 'fLaC' magic and STREAMINFO block get combined into the first
+ *   packet.  The packet is prefixed with
+ *   + the one-byte packet type 0x7F
+ *   + 'FLAC' magic
+ *   + the 2 byte Ogg FLAC mapping version number
+ *   + tne 2 byte big-endian # of header packets
+ * - The first packet is flushed to the first page.
+ * - Each subsequent metadata block goes into its own packet.
+ * - Each metadata packet is flushed to page (this is not required,
+ *   the mapping only requires that a flush must occur after all
+ *   metadata is written).
+ * - Each subsequent FLAC audio frame goes into its own packet.
+ *
+ * WATCHOUT:
+ * This depends on the behavior of FLAC__StreamEncoder that we get a
+ * separate write callback for the fLaC magic, and then separate write
+ * callbacks for each metadata block and audio frame.
+ */
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data)
+{
+       /* WATCHOUT:
+        * This depends on the behavior of FLAC__StreamEncoder that 'samples'
+        * will be 0 for metadata writes.
+        */
+       const FLAC__bool is_metadata = (samples == 0);
+
+       /*
+        * Treat fLaC magic packet specially.  We will note when we see it, then
+        * wait until we get the STREAMINFO and prepend it in that packet
+        */
+       if(aspect->seen_magic) {
+               ogg_packet packet;
+               FLAC__byte synthetic_first_packet_body[
+                       FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+                       FLAC__OGG_MAPPING_MAGIC_LENGTH +
+                       FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+                       FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+                       FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+                       FLAC__STREAM_SYNC_LENGTH +
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       FLAC__STREAM_METADATA_STREAMINFO_LENGTH
+               ];
+
+               memset(&packet, 0, sizeof(packet));
+               packet.granulepos = aspect->samples_written + samples;
+
+               if(aspect->is_first_packet) {
+                       FLAC__byte *b = synthetic_first_packet_body;
+                       if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) {
+                               /*
+                                * If we get here, our assumption about the way write callbacks happen
+                                * (explained above) is wrong
+                                */
+                               FLAC__ASSERT(0);
+                               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                       }
+                       /* add first header packet type */
+                       *b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE;
+                       b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+                       /* add 'FLAC' mapping magic */
+                       memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH);
+                       b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+                       /* add Ogg FLAC mapping major version number */
+                       memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH);
+                       b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+                       /* add Ogg FLAC mapping minor version number */
+                       memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH);
+                       b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH;
+                       /* add number of header packets */
+                       *b = (FLAC__byte)(aspect->num_metadata >> 8);
+                       b++;
+                       *b = (FLAC__byte)(aspect->num_metadata);
+                       b++;
+                       /* add native FLAC 'fLaC' magic */
+                       memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH);
+                       b += FLAC__STREAM_SYNC_LENGTH;
+                       /* add STREAMINFO */
+                       memcpy(b, buffer, bytes);
+                       FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body));
+                       packet.packet = (unsigned char *)synthetic_first_packet_body;
+                       packet.bytes = sizeof(synthetic_first_packet_body);
+
+                       packet.b_o_s = 1;
+                       aspect->is_first_packet = false;
+               }
+               else {
+                       packet.packet = (unsigned char *)buffer;
+                       packet.bytes = bytes;
+               }
+
+               if(is_last_block) {
+                       /* we used to check:
+                        * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples);
+                        * but it's really not useful since total_samples_estimate is an estimate and can be inexact
+                        */
+                       packet.e_o_s = 1;
+               }
+
+               if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0)
+                       return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+               /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */
+               if(is_metadata) {
+                       while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) {
+                               if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+                                       return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                               if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+                                       return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                       }
+               }
+               else {
+                       while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) {
+                               if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+                                       return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                               if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+                                       return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+                       }
+               }
+       }
+       else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) {
+               aspect->seen_magic = true;
+       }
+       else {
+               /*
+                * If we get here, our assumption about the way write callbacks happen
+                * explained above is wrong
+                */
+               FLAC__ASSERT(0);
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+       }
+
+       aspect->samples_written += samples;
+
+       return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
diff --git a/src/libFLAC/ogg_helper.c b/src/libFLAC/ogg_helper.c
new file mode 100644 (file)
index 0000000..73f9f0b
--- /dev/null
@@ -0,0 +1,209 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp(), memcpy() */
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "private/ogg_helper.h"
+#include "protected/stream_encoder.h"
+
+
+static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+       while(bytes > 0) {
+               size_t bytes_read = bytes;
+               switch(read_callback(encoder, buffer, &bytes_read, client_data)) {
+                       case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE:
+                               bytes -= bytes_read;
+                               buffer += bytes_read;
+                               break;
+                       case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM:
+                               if(bytes_read == 0) {
+                                       encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                                       return false;
+                               }
+                               bytes -= bytes_read;
+                               buffer += bytes_read;
+                               break;
+                       case FLAC__STREAM_ENCODER_READ_STATUS_ABORT:
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                               return false;
+                       case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED:
+                               return false;
+                       default:
+                               /* double protection: */
+                               FLAC__ASSERT(0);
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+void simple_ogg_page__init(ogg_page *page)
+{
+       page->header = 0;
+       page->header_len = 0;
+       page->body = 0;
+       page->body_len = 0;
+}
+
+void simple_ogg_page__clear(ogg_page *page)
+{
+       if(page->header)
+               free(page->header);
+       if(page->body)
+               free(page->body);
+       simple_ogg_page__init(page);
+}
+
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+       static const unsigned OGG_HEADER_FIXED_PORTION_LEN = 27;
+       static const unsigned OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255;
+       FLAC__byte crc[4];
+       FLAC__StreamEncoderSeekStatus seek_status;
+
+       FLAC__ASSERT(page->header == 0);
+       FLAC__ASSERT(page->header_len == 0);
+       FLAC__ASSERT(page->body == 0);
+       FLAC__ASSERT(page->body_len == 0);
+
+       /* move the stream pointer to the supposed beginning of the page */
+       if(0 == seek_callback)
+               return false;
+       if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+               if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return false;
+       }
+
+       /* allocate space for the page header */
+       if(0 == (page->header = (unsigned char *)safe_malloc_(OGG_MAX_HEADER_LEN))) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       /* read in the fixed part of the page header (up to but not including
+        * the segment table */
+       if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data))
+               return false;
+
+       page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26];
+
+       /* check to see if it's a correct, "simple" page (one packet only) */
+       if(
+               memcmp(page->header, "OggS", 4) ||               /* doesn't start with OggS */
+               (page->header[5] & 0x01) ||                      /* continued packet */
+               memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */
+               page->header[26] == 0                            /* packet is 0-size */
+       ) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+               return false;
+       }
+
+       /* read in the segment table */
+       if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data))
+               return false;
+
+       {
+               unsigned i;
+
+               /* check to see that it specifies a single packet */
+               for(i = 0; i < (unsigned)page->header[26] - 1; i++) {
+                       if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                               return false;
+                       }
+               }
+
+               page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN];
+       }
+
+       /* allocate space for the page body */
+       if(0 == (page->body = (unsigned char *)safe_malloc_(page->body_len))) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       /* read in the page body */
+       if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data))
+               return false;
+
+       /* check the CRC */
+       memcpy(crc, page->header+22, 4);
+       ogg_page_checksum_set(page);
+       if(memcmp(crc, page->header+22, 4)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+               return false;
+       }
+
+       return true;
+}
+
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data)
+{
+       FLAC__StreamEncoderSeekStatus seek_status;
+
+       FLAC__ASSERT(page->header != 0);
+       FLAC__ASSERT(page->header_len != 0);
+       FLAC__ASSERT(page->body != 0);
+       FLAC__ASSERT(page->body_len != 0);
+
+       /* move the stream pointer to the supposed beginning of the page */
+       if(0 == seek_callback)
+               return false;
+       if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+               if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return false;
+       }
+
+       ogg_page_checksum_set(page);
+
+       /* re-write the page */
+       if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return false;
+       }
+       if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return false;
+       }
+
+       return true;
+}
diff --git a/src/libFLAC/ogg_mapping.c b/src/libFLAC/ogg_mapping.c
new file mode 100644 (file)
index 0000000..a518892
--- /dev/null
@@ -0,0 +1,47 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/ogg_mapping.h"
+
+const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN = 8; /* bits */
+
+const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE = 0x7f;
+
+const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC = (const FLAC__byte * const)"FLAC";
+
+const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */
+const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */
+
+const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */
diff --git a/src/libFLAC/ppc/Makefile.am b/src/libFLAC/ppc/Makefile.am
new file mode 100644 (file)
index 0000000..87cd95c
--- /dev/null
@@ -0,0 +1,31 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SUBDIRS = as gas
diff --git a/src/libFLAC/ppc/as/Makefile.am b/src/libFLAC/ppc/as/Makefile.am
new file mode 100644 (file)
index 0000000..919938b
--- /dev/null
@@ -0,0 +1,52 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#@@@
+if FLaC__HAS_AS__TEMPORARILY_DISABLED
+
+SUFFIXES = .s .lo
+
+STRIP_NON_ASM = sh $(top_srcdir)/strip_non_asm_libtool_args.sh
+
+# For some unknown reason libtool can't figure out the tag for 'as', so
+# we fake it with --tag=CC and strip out unwanted options.
+.s.lo:
+       $(LIBTOOL) --tag=CC --mode=compile $(STRIP_NON_ASM) as -force_cpusubtype_ALL -o $@ $<
+
+noinst_LTLIBRARIES = libFLAC-asm.la
+libFLAC_asm_la_SOURCES = \
+       lpc_asm.s
+
+else
+
+EXTRA_DIST = \
+       lpc_asm.s
+
+endif
diff --git a/src/libFLAC/ppc/as/lpc_asm.s b/src/libFLAC/ppc/as/lpc_asm.s
new file mode 100644 (file)
index 0000000..ca39c6f
--- /dev/null
@@ -0,0 +1,429 @@
+;  libFLAC - Free Lossless Audio Codec library
+;  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+;
+;  Redistribution and use in source and binary forms, with or without
+;  modification, are permitted provided that the following conditions
+;  are met:
+;
+;  - Redistributions of source code must retain the above copyright
+;  notice, this list of conditions and the following disclaimer.
+;
+;  - Redistributions in binary form must reproduce the above copyright
+;  notice, this list of conditions and the following disclaimer in the
+;  documentation and/or other materials provided with the distribution.
+;
+;  - Neither the name of the Xiph.org Foundation nor the names of its
+;  contributors may be used to endorse or promote products derived from
+;  this software without specific prior written permission.
+;
+;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.text
+       .align 2
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16
+
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16:
+;      r3: residual[]
+;      r4: data_len
+;      r5: qlp_coeff[]
+;      r6: order
+;      r7: lp_quantization
+;      r8: data[]
+
+; see src/libFLAC/lpc.c:FLAC__lpc_restore_signal()
+; these is a PowerPC/Altivec assembly version which requires bps<=16 (or actual
+; bps<=15 for mid-side coding, since that uses an extra bit)
+
+; these should be fast; the inner loop is unrolled (it takes no more than
+; 3*(order%4) instructions, all of which are arithmetic), and all of the
+; coefficients and all relevant history stay in registers, so the outer loop
+; has only one load from memory (the residual)
+
+; I have not yet run this through simg4, so there may be some avoidable stalls,
+; and there may be a somewhat more clever way to do the outer loop
+
+; the branch mechanism may prevent dynamic loading; I still need to examine
+; this issue, and there may be a more elegant method
+
+       stmw r31,-4(r1)
+
+       addi r9,r1,-28
+       li r31,0xf
+       andc r9,r9,r31 ; for quadword-aligned stack data
+
+       slwi r6,r6,2 ; adjust for word size
+       slwi r4,r4,2
+       add r4,r4,r8 ; r4 = data+data_len
+
+       mfspr r0,256 ; cache old vrsave
+       addis r31,0,hi16(0xfffffc00)
+       ori r31,r31,lo16(0xfffffc00)
+       mtspr 256,r31 ; declare VRs in vrsave
+
+       cmplw cr0,r8,r4 ; i<data_len
+       bc 4,0,L1400
+
+       ; load coefficients into v0-v7 and initial history into v8-v15
+       li r31,0xf
+       and r31,r8,r31 ; r31: data%4
+       li r11,16
+       subf r31,r31,r11 ; r31: 4-(data%4)
+       slwi r31,r31,3 ; convert to bits for vsro
+       li r10,-4
+       stw r31,-4(r9)
+       lvewx v0,r10,r9
+       vspltisb v18,-1
+       vsro v18,v18,v0 ; v18: mask vector
+
+       li r31,0x8
+       lvsl v0,0,r31
+       vsldoi v0,v0,v0,12
+       li r31,0xc
+       lvsl v1,0,r31
+       vspltisb v2,0
+       vspltisb v3,-1
+       vmrglw v2,v2,v3
+       vsel v0,v1,v0,v2 ; v0: reversal permutation vector
+
+       add r10,r5,r6
+       lvsl v17,0,r5 ; v17: coefficient alignment permutation vector
+       vperm v17,v17,v17,v0 ; v17: reversal coefficient alignment permutation vector
+
+       mr r11,r8
+       lvsl v16,0,r11 ; v16: history alignment permutation vector
+
+       lvx v0,0,r5
+       addi r5,r5,16
+       lvx v1,0,r5
+       vperm v0,v0,v1,v17
+       lvx v8,0,r11
+       addi r11,r11,-16
+       lvx v9,0,r11
+       vperm v8,v9,v8,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1101
+       vand v0,v0,v18
+       addis r31,0,hi16(L1307)
+       ori r31,r31,lo16(L1307)
+       b L1199
+
+L1101:
+       addi r5,r5,16
+       lvx v2,0,r5
+       vperm v1,v1,v2,v17
+       addi r11,r11,-16
+       lvx v10,0,r11
+       vperm v9,v10,v9,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1102
+       vand v1,v1,v18
+       addis r31,0,hi16(L1306)
+       ori r31,r31,lo16(L1306)
+       b L1199
+
+L1102:
+       addi r5,r5,16
+       lvx v3,0,r5
+       vperm v2,v2,v3,v17
+       addi r11,r11,-16
+       lvx v11,0,r11
+       vperm v10,v11,v10,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1103
+       vand v2,v2,v18
+       addis r31,0,hi16(L1305)
+       ori r31,r31,lo16(L1305)
+       b L1199
+
+L1103:
+       addi r5,r5,16
+       lvx v4,0,r5
+       vperm v3,v3,v4,v17
+       addi r11,r11,-16
+       lvx v12,0,r11
+       vperm v11,v12,v11,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1104
+       vand v3,v3,v18
+       addis r31,0,hi16(L1304)
+       ori r31,r31,lo16(L1304)
+       b L1199
+
+L1104:
+       addi r5,r5,16
+       lvx v5,0,r5
+       vperm v4,v4,v5,v17
+       addi r11,r11,-16
+       lvx v13,0,r11
+       vperm v12,v13,v12,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1105
+       vand v4,v4,v18
+       addis r31,0,hi16(L1303)
+       ori r31,r31,lo16(L1303)
+       b L1199
+
+L1105:
+       addi r5,r5,16
+       lvx v6,0,r5
+       vperm v5,v5,v6,v17
+       addi r11,r11,-16
+       lvx v14,0,r11
+       vperm v13,v14,v13,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1106
+       vand v5,v5,v18
+       addis r31,0,hi16(L1302)
+       ori r31,r31,lo16(L1302)
+       b L1199
+
+L1106:
+       addi r5,r5,16
+       lvx v7,0,r5
+       vperm v6,v6,v7,v17
+       addi r11,r11,-16
+       lvx v15,0,r11
+       vperm v14,v15,v14,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1107
+       vand v6,v6,v18
+       addis r31,0,hi16(L1301)
+       ori r31,r31,lo16(L1301)
+       b L1199
+
+L1107:
+       addi r5,r5,16
+       lvx v19,0,r5
+       vperm v7,v7,v19,v17
+       addi r11,r11,-16
+       lvx v19,0,r11
+       vperm v15,v19,v15,v16
+       vand v7,v7,v18
+       addis r31,0,hi16(L1300)
+       ori r31,r31,lo16(L1300)
+
+L1199:
+       mtctr r31
+
+       ; set up invariant vectors
+       vspltish v16,0 ; v16: zero vector
+
+       li r10,-12
+       lvsr v17,r10,r8 ; v17: result shift vector
+       lvsl v18,r10,r3 ; v18: residual shift back vector
+
+       li r10,-4
+       stw r7,-4(r9)
+       lvewx v19,r10,r9 ; v19: lp_quantization vector
+
+L1200:
+       vmulosh v20,v0,v8 ; v20: sum vector
+       bcctr 20,0
+
+L1300:
+       vmulosh v21,v7,v15
+       vsldoi v15,v15,v14,4 ; increment history
+       vaddsws v20,v20,v21
+
+L1301:
+       vmulosh v21,v6,v14
+       vsldoi v14,v14,v13,4
+       vaddsws v20,v20,v21
+
+L1302:
+       vmulosh v21,v5,v13
+       vsldoi v13,v13,v12,4
+       vaddsws v20,v20,v21
+
+L1303:
+       vmulosh v21,v4,v12
+       vsldoi v12,v12,v11,4
+       vaddsws v20,v20,v21
+
+L1304:
+       vmulosh v21,v3,v11
+       vsldoi v11,v11,v10,4
+       vaddsws v20,v20,v21
+
+L1305:
+       vmulosh v21,v2,v10
+       vsldoi v10,v10,v9,4
+       vaddsws v20,v20,v21
+
+L1306:
+       vmulosh v21,v1,v9
+       vsldoi v9,v9,v8,4
+       vaddsws v20,v20,v21
+
+L1307:
+       vsumsws v20,v20,v16 ; v20[3]: sum
+       vsraw v20,v20,v19 ; v20[3]: sum >> lp_quantization
+
+       lvewx v21,0,r3 ; v21[n]: *residual
+       vperm v21,v21,v21,v18 ; v21[3]: *residual
+       vaddsws v20,v21,v20 ; v20[3]: *residual + (sum >> lp_quantization)
+       vsldoi v18,v18,v18,4 ; increment shift vector
+
+       vperm v21,v20,v20,v17 ; v21[n]: shift for storage
+       vsldoi v17,v17,v17,12 ; increment shift vector
+       stvewx v21,0,r8
+
+       vsldoi v20,v20,v20,12
+       vsldoi v8,v8,v20,4 ; insert value onto history
+
+       addi r3,r3,4
+       addi r8,r8,4
+       cmplw cr0,r8,r4 ; i<data_len
+       bc 12,0,L1200
+
+L1400:
+       mtspr 256,r0 ; restore old vrsave
+       lmw r31,-4(r1)
+       blr
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8:
+;      r3: residual[]
+;      r4: data_len
+;      r5: qlp_coeff[]
+;      r6: order
+;      r7: lp_quantization
+;      r8: data[]
+
+; see _FLAC__lpc_restore_signal_asm_ppc_altivec_16() above
+; this version assumes order<=8; it uses fewer vector registers, which should
+; save time in context switches, and has less code, which may improve
+; instruction caching
+
+       stmw r31,-4(r1)
+
+       addi r9,r1,-28
+       li r31,0xf
+       andc r9,r9,r31 ; for quadword-aligned stack data
+
+       slwi r6,r6,2 ; adjust for word size
+       slwi r4,r4,2
+       add r4,r4,r8 ; r4 = data+data_len
+
+       mfspr r0,256 ; cache old vrsave
+       addis r31,0,hi16(0xffc00000)
+       ori r31,r31,lo16(0xffc00000)
+       mtspr 256,r31 ; declare VRs in vrsave
+
+       cmplw cr0,r8,r4 ; i<data_len
+       bc 4,0,L2400
+
+       ; load coefficients into v0-v1 and initial history into v2-v3
+       li r31,0xf
+       and r31,r8,r31 ; r31: data%4
+       li r11,16
+       subf r31,r31,r11 ; r31: 4-(data%4)
+       slwi r31,r31,3 ; convert to bits for vsro
+       li r10,-4
+       stw r31,-4(r9)
+       lvewx v0,r10,r9
+       vspltisb v6,-1
+       vsro v6,v6,v0 ; v6: mask vector
+
+       li r31,0x8
+       lvsl v0,0,r31
+       vsldoi v0,v0,v0,12
+       li r31,0xc
+       lvsl v1,0,r31
+       vspltisb v2,0
+       vspltisb v3,-1
+       vmrglw v2,v2,v3
+       vsel v0,v1,v0,v2 ; v0: reversal permutation vector
+
+       add r10,r5,r6
+       lvsl v5,0,r5 ; v5: coefficient alignment permutation vector
+       vperm v5,v5,v5,v0 ; v5: reversal coefficient alignment permutation vector
+
+       mr r11,r8
+       lvsl v4,0,r11 ; v4: history alignment permutation vector
+
+       lvx v0,0,r5
+       addi r5,r5,16
+       lvx v1,0,r5
+       vperm v0,v0,v1,v5
+       lvx v2,0,r11
+       addi r11,r11,-16
+       lvx v3,0,r11
+       vperm v2,v3,v2,v4
+       cmplw cr0,r5,r10
+       bc 12,0,L2101
+       vand v0,v0,v6
+       addis r31,0,hi16(L2301)
+       ori r31,r31,lo16(L2301)
+       b L2199
+
+L2101:
+       addi r5,r5,16
+       lvx v7,0,r5
+       vperm v1,v1,v7,v5
+       addi r11,r11,-16
+       lvx v7,0,r11
+       vperm v3,v7,v3,v4
+       vand v1,v1,v6
+       addis r31,0,hi16(L2300)
+       ori r31,r31,lo16(L2300)
+
+L2199:
+       mtctr r31
+
+       ; set up invariant vectors
+       vspltish v4,0 ; v4: zero vector
+
+       li r10,-12
+       lvsr v5,r10,r8 ; v5: result shift vector
+       lvsl v6,r10,r3 ; v6: residual shift back vector
+
+       li r10,-4
+       stw r7,-4(r9)
+       lvewx v7,r10,r9 ; v7: lp_quantization vector
+
+L2200:
+       vmulosh v8,v0,v2 ; v8: sum vector
+       bcctr 20,0
+
+L2300:
+       vmulosh v9,v1,v3
+       vsldoi v3,v3,v2,4
+       vaddsws v8,v8,v9
+
+L2301:
+       vsumsws v8,v8,v4 ; v8[3]: sum
+       vsraw v8,v8,v7 ; v8[3]: sum >> lp_quantization
+
+       lvewx v9,0,r3 ; v9[n]: *residual
+       vperm v9,v9,v9,v6 ; v9[3]: *residual
+       vaddsws v8,v9,v8 ; v8[3]: *residual + (sum >> lp_quantization)
+       vsldoi v6,v6,v6,4 ; increment shift vector
+
+       vperm v9,v8,v8,v5 ; v9[n]: shift for storage
+       vsldoi v5,v5,v5,12 ; increment shift vector
+       stvewx v9,0,r8
+
+       vsldoi v8,v8,v8,12
+       vsldoi v2,v2,v8,4 ; insert value onto history
+
+       addi r3,r3,4
+       addi r8,r8,4
+       cmplw cr0,r8,r4 ; i<data_len
+       bc 12,0,L2200
+
+L2400:
+       mtspr 256,r0 ; restore old vrsave
+       lmw r31,-4(r1)
+       blr
diff --git a/src/libFLAC/ppc/gas/Makefile.am b/src/libFLAC/ppc/gas/Makefile.am
new file mode 100644 (file)
index 0000000..3a66c27
--- /dev/null
@@ -0,0 +1,52 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#@@@
+if FLaC__HAS_GAS__TEMPORARILY_DISABLED
+
+SUFFIXES = .s .lo
+
+STRIP_NON_ASM = sh $(top_srcdir)/strip_non_asm_libtool_args.sh
+
+# For some unknown reason libtool can't figure out the tag for 'gas', so
+# we fake it with --tag=CC and strip out unwanted options.
+.s.lo:
+       $(LIBTOOL) --tag=CC --mode=compile $(STRIP_NON_ASM) gas -force_cpusubtype_ALL -o $@ $<
+
+noinst_LTLIBRARIES = libFLAC-asm.la
+libFLAC_asm_la_SOURCES = \
+       lpc_asm.s
+
+else
+
+EXTRA_DIST = \
+       lpc_asm.s
+
+endif
diff --git a/src/libFLAC/ppc/gas/lpc_asm.s b/src/libFLAC/ppc/gas/lpc_asm.s
new file mode 100644 (file)
index 0000000..2203570
--- /dev/null
@@ -0,0 +1,431 @@
+#  libFLAC - Free Lossless Audio Codec library
+#  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of the Xiph.org Foundation nor the names of its
+#  contributors may be used to endorse or promote products derived from
+#  this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.text
+       .align 2
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16
+.type _FLAC__lpc_restore_signal_asm_ppc_altivec_16, @function
+
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8
+.type _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8, @function
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16:
+#      r3: residual[]
+#      r4: data_len
+#      r5: qlp_coeff[]
+#      r6: order
+#      r7: lp_quantization
+#      r8: data[]
+
+# see src/libFLAC/lpc.c:FLAC__lpc_restore_signal()
+# these is a PowerPC/Altivec assembly version which requires bps<=16 (or actual
+# bps<=15 for mid-side coding, since that uses an extra bit)
+
+# these should be fast; the inner loop is unrolled (it takes no more than
+# 3*(order%4) instructions, all of which are arithmetic), and all of the
+# coefficients and all relevant history stay in registers, so the outer loop
+# has only one load from memory (the residual)
+
+# I have not yet run this through simg4, so there may be some avoidable stalls,
+# and there may be a somewhat more clever way to do the outer loop
+
+# the branch mechanism may prevent dynamic loading; I still need to examine
+# this issue, and there may be a more elegant method
+
+       stmw r31,-4(r1)
+
+       addi r9,r1,-28
+       li r31,0xf
+       andc r9,r9,r31 # for quadword-aligned stack data
+
+       slwi r6,r6,2 # adjust for word size
+       slwi r4,r4,2
+       add r4,r4,r8 # r4 = data+data_len
+
+       mfspr r0,256 # cache old vrsave
+       addis r31,0,0xffff
+       ori r31,r31,0xfc00
+       mtspr 256,r31 # declare VRs in vrsave
+
+       cmplw cr0,r8,r4 # i<data_len
+       bc 4,0,L1400
+
+       # load coefficients into v0-v7 and initial history into v8-v15
+       li r31,0xf
+       and r31,r8,r31 # r31: data%4
+       li r11,16
+       subf r31,r31,r11 # r31: 4-(data%4)
+       slwi r31,r31,3 # convert to bits for vsro
+       li r10,-4
+       stw r31,-4(r9)
+       lvewx v0,r10,r9
+       vspltisb v18,-1
+       vsro v18,v18,v0 # v18: mask vector
+
+       li r31,0x8
+       lvsl v0,0,r31
+       vsldoi v0,v0,v0,12
+       li r31,0xc
+       lvsl v1,0,r31
+       vspltisb v2,0
+       vspltisb v3,-1
+       vmrglw v2,v2,v3
+       vsel v0,v1,v0,v2 # v0: reversal permutation vector
+
+       add r10,r5,r6
+       lvsl v17,0,r5 # v17: coefficient alignment permutation vector
+       vperm v17,v17,v17,v0 # v17: reversal coefficient alignment permutation vector
+
+       mr r11,r8
+       lvsl v16,0,r11 # v16: history alignment permutation vector
+
+       lvx v0,0,r5
+       addi r5,r5,16
+       lvx v1,0,r5
+       vperm v0,v0,v1,v17
+       lvx v8,0,r11
+       addi r11,r11,-16
+       lvx v9,0,r11
+       vperm v8,v9,v8,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1101
+       vand v0,v0,v18
+       addis r31,0,L1307@ha
+       ori r31,r31,L1307@l
+       b L1199
+
+L1101:
+       addi r5,r5,16
+       lvx v2,0,r5
+       vperm v1,v1,v2,v17
+       addi r11,r11,-16
+       lvx v10,0,r11
+       vperm v9,v10,v9,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1102
+       vand v1,v1,v18
+       addis r31,0,L1306@ha
+       ori r31,r31,L1306@l
+       b L1199
+
+L1102:
+       addi r5,r5,16
+       lvx v3,0,r5
+       vperm v2,v2,v3,v17
+       addi r11,r11,-16
+       lvx v11,0,r11
+       vperm v10,v11,v10,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1103
+       vand v2,v2,v18
+       lis r31,L1305@ha
+       la r31,L1305@l(r31)
+       b L1199
+
+L1103:
+       addi r5,r5,16
+       lvx v4,0,r5
+       vperm v3,v3,v4,v17
+       addi r11,r11,-16
+       lvx v12,0,r11
+       vperm v11,v12,v11,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1104
+       vand v3,v3,v18
+       lis r31,L1304@ha
+       la r31,L1304@l(r31)
+       b L1199
+
+L1104:
+       addi r5,r5,16
+       lvx v5,0,r5
+       vperm v4,v4,v5,v17
+       addi r11,r11,-16
+       lvx v13,0,r11
+       vperm v12,v13,v12,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1105
+       vand v4,v4,v18
+       lis r31,L1303@ha
+       la r31,L1303@l(r31)
+       b L1199
+
+L1105:
+       addi r5,r5,16
+       lvx v6,0,r5
+       vperm v5,v5,v6,v17
+       addi r11,r11,-16
+       lvx v14,0,r11
+       vperm v13,v14,v13,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1106
+       vand v5,v5,v18
+       lis r31,L1302@ha
+       la r31,L1302@l(r31)
+       b L1199
+
+L1106:
+       addi r5,r5,16
+       lvx v7,0,r5
+       vperm v6,v6,v7,v17
+       addi r11,r11,-16
+       lvx v15,0,r11
+       vperm v14,v15,v14,v16
+       cmplw cr0,r5,r10
+       bc 12,0,L1107
+       vand v6,v6,v18
+       lis r31,L1301@ha
+       la r31,L1301@l(r31)
+       b L1199
+
+L1107:
+       addi r5,r5,16
+       lvx v19,0,r5
+       vperm v7,v7,v19,v17
+       addi r11,r11,-16
+       lvx v19,0,r11
+       vperm v15,v19,v15,v16
+       vand v7,v7,v18
+       lis r31,L1300@ha
+       la r31,L1300@l(r31)
+
+L1199:
+       mtctr r31
+
+       # set up invariant vectors
+       vspltish v16,0 # v16: zero vector
+
+       li r10,-12
+       lvsr v17,r10,r8 # v17: result shift vector
+       lvsl v18,r10,r3 # v18: residual shift back vector
+
+       li r10,-4
+       stw r7,-4(r9)
+       lvewx v19,r10,r9 # v19: lp_quantization vector
+
+L1200:
+       vmulosh v20,v0,v8 # v20: sum vector
+       bcctr 20,0
+
+L1300:
+       vmulosh v21,v7,v15
+       vsldoi v15,v15,v14,4 # increment history
+       vaddsws v20,v20,v21
+
+L1301:
+       vmulosh v21,v6,v14
+       vsldoi v14,v14,v13,4
+       vaddsws v20,v20,v21
+
+L1302:
+       vmulosh v21,v5,v13
+       vsldoi v13,v13,v12,4
+       vaddsws v20,v20,v21
+
+L1303:
+       vmulosh v21,v4,v12
+       vsldoi v12,v12,v11,4
+       vaddsws v20,v20,v21
+
+L1304:
+       vmulosh v21,v3,v11
+       vsldoi v11,v11,v10,4
+       vaddsws v20,v20,v21
+
+L1305:
+       vmulosh v21,v2,v10
+       vsldoi v10,v10,v9,4
+       vaddsws v20,v20,v21
+
+L1306:
+       vmulosh v21,v1,v9
+       vsldoi v9,v9,v8,4
+       vaddsws v20,v20,v21
+
+L1307:
+       vsumsws v20,v20,v16 # v20[3]: sum
+       vsraw v20,v20,v19 # v20[3]: sum >> lp_quantization
+
+       lvewx v21,0,r3 # v21[n]: *residual
+       vperm v21,v21,v21,v18 # v21[3]: *residual
+       vaddsws v20,v21,v20 # v20[3]: *residual + (sum >> lp_quantization)
+       vsldoi v18,v18,v18,4 # increment shift vector
+
+       vperm v21,v20,v20,v17 # v21[n]: shift for storage
+       vsldoi v17,v17,v17,12 # increment shift vector
+       stvewx v21,0,r8
+
+       vsldoi v20,v20,v20,12
+       vsldoi v8,v8,v20,4 # insert value onto history
+
+       addi r3,r3,4
+       addi r8,r8,4
+       cmplw cr0,r8,r4 # i<data_len
+       bc 12,0,L1200
+
+L1400:
+       mtspr 256,r0 # restore old vrsave
+       lmw r31,-4(r1)
+       blr
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8:
+#      r3: residual[]
+#      r4: data_len
+#      r5: qlp_coeff[]
+#      r6: order
+#      r7: lp_quantization
+#      r8: data[]
+
+# see _FLAC__lpc_restore_signal_asm_ppc_altivec_16() above
+# this version assumes order<=8; it uses fewer vector registers, which should
+# save time in context switches, and has less code, which may improve
+# instruction caching
+
+       stmw r31,-4(r1)
+
+       addi r9,r1,-28
+       li r31,0xf
+       andc r9,r9,r31 # for quadword-aligned stack data
+
+       slwi r6,r6,2 # adjust for word size
+       slwi r4,r4,2
+       add r4,r4,r8 # r4 = data+data_len
+
+       mfspr r0,256 # cache old vrsave
+       addis r31,0,0xffc0
+       ori r31,r31,0x0000
+       mtspr 256,r31 # declare VRs in vrsave
+
+       cmplw cr0,r8,r4 # i<data_len
+       bc 4,0,L2400
+
+       # load coefficients into v0-v1 and initial history into v2-v3
+       li r31,0xf
+       and r31,r8,r31 # r31: data%4
+       li r11,16
+       subf r31,r31,r11 # r31: 4-(data%4)
+       slwi r31,r31,3 # convert to bits for vsro
+       li r10,-4
+       stw r31,-4(r9)
+       lvewx v0,r10,r9
+       vspltisb v6,-1
+       vsro v6,v6,v0 # v6: mask vector
+
+       li r31,0x8
+       lvsl v0,0,r31
+       vsldoi v0,v0,v0,12
+       li r31,0xc
+       lvsl v1,0,r31
+       vspltisb v2,0
+       vspltisb v3,-1
+       vmrglw v2,v2,v3
+       vsel v0,v1,v0,v2 # v0: reversal permutation vector
+
+       add r10,r5,r6
+       lvsl v5,0,r5 # v5: coefficient alignment permutation vector
+       vperm v5,v5,v5,v0 # v5: reversal coefficient alignment permutation vector
+
+       mr r11,r8
+       lvsl v4,0,r11 # v4: history alignment permutation vector
+
+       lvx v0,0,r5
+       addi r5,r5,16
+       lvx v1,0,r5
+       vperm v0,v0,v1,v5
+       lvx v2,0,r11
+       addi r11,r11,-16
+       lvx v3,0,r11
+       vperm v2,v3,v2,v4
+       cmplw cr0,r5,r10
+       bc 12,0,L2101
+       vand v0,v0,v6
+       lis r31,L2301@ha
+       la r31,L2301@l(r31)
+       b L2199
+
+L2101:
+       addi r5,r5,16
+       lvx v7,0,r5
+       vperm v1,v1,v7,v5
+       addi r11,r11,-16
+       lvx v7,0,r11
+       vperm v3,v7,v3,v4
+       vand v1,v1,v6
+       lis r31,L2300@ha
+       la r31,L2300@l(r31)
+
+L2199:
+       mtctr r31
+
+       # set up invariant vectors
+       vspltish v4,0 # v4: zero vector
+
+       li r10,-12
+       lvsr v5,r10,r8 # v5: result shift vector
+       lvsl v6,r10,r3 # v6: residual shift back vector
+
+       li r10,-4
+       stw r7,-4(r9)
+       lvewx v7,r10,r9 # v7: lp_quantization vector
+
+L2200:
+       vmulosh v8,v0,v2 # v8: sum vector
+       bcctr 20,0
+
+L2300:
+       vmulosh v9,v1,v3
+       vsldoi v3,v3,v2,4
+       vaddsws v8,v8,v9
+
+L2301:
+       vsumsws v8,v8,v4 # v8[3]: sum
+       vsraw v8,v8,v7 # v8[3]: sum >> lp_quantization
+
+       lvewx v9,0,r3 # v9[n]: *residual
+       vperm v9,v9,v9,v6 # v9[3]: *residual
+       vaddsws v8,v9,v8 # v8[3]: *residual + (sum >> lp_quantization)
+       vsldoi v6,v6,v6,4 # increment shift vector
+
+       vperm v9,v8,v8,v5 # v9[n]: shift for storage
+       vsldoi v5,v5,v5,12 # increment shift vector
+       stvewx v9,0,r8
+
+       vsldoi v8,v8,v8,12
+       vsldoi v2,v2,v8,4 # insert value onto history
+
+       addi r3,r3,4
+       addi r8,r8,4
+       cmplw cr0,r8,r4 # i<data_len
+       bc 12,0,L2200
+
+L2400:
+       mtspr 256,r0 # restore old vrsave
+       lmw r31,-4(r1)
+       blr
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
new file mode 100644 (file)
index 0000000..4d86fda
--- /dev/null
@@ -0,0 +1,3387 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include <sys/stat.h> /* for stat() */
+#include <sys/types.h> /* for off_t */
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "protected/stream_decoder.h"
+#include "private/bitreader.h"
+#include "private/bitmath.h"
+#include "private/cpu.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+
+/* technically this should be in an "export.c" but this is convenient enough */
+FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC =
+#if FLAC__HAS_OGG
+       1
+#else
+       0
+#endif
+;
+
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj);
+static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj);
+static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended);
+static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data);
+#if FLAC__HAS_OGG
+static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes);
+static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+#endif
+static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status);
+static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#if FLAC__HAS_OGG
+static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#endif
+static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+#if FLAC__HAS_OGG
+       FLAC__bool is_ogg;
+#endif
+       FLAC__StreamDecoderReadCallback read_callback;
+       FLAC__StreamDecoderSeekCallback seek_callback;
+       FLAC__StreamDecoderTellCallback tell_callback;
+       FLAC__StreamDecoderLengthCallback length_callback;
+       FLAC__StreamDecoderEofCallback eof_callback;
+       FLAC__StreamDecoderWriteCallback write_callback;
+       FLAC__StreamDecoderMetadataCallback metadata_callback;
+       FLAC__StreamDecoderErrorCallback error_callback;
+       /* generic 32-bit datapath: */
+       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[]);
+       /* generic 64-bit datapath: */
+       void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+       /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
+       void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+       /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */
+       void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+       FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+       void *client_data;
+       FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */
+       FLAC__BitReader *input;
+       FLAC__int32 *output[FLAC__MAX_CHANNELS];
+       FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
+       FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+       unsigned output_capacity, output_channels;
+       FLAC__uint32 fixed_block_size, next_fixed_block_size;
+       FLAC__uint64 samples_decoded;
+       FLAC__bool has_stream_info, has_seek_table;
+       FLAC__StreamMetadata stream_info;
+       FLAC__StreamMetadata seek_table;
+       FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
+       FLAC__byte *metadata_filter_ids;
+       size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
+       FLAC__Frame frame;
+       FLAC__bool cached; /* true if there is a byte in lookahead */
+       FLAC__CPUInfo cpuinfo;
+       FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+       FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+       /* unaligned (original) pointers to allocated data */
+       FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+       FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */
+       FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */
+       FLAC__bool is_seeking;
+       FLAC__MD5Context md5context;
+       FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
+       /* (the rest of these are only used for seeking) */
+       FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
+       FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+       FLAC__uint64 target_sample;
+       unsigned unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+#if FLAC__HAS_OGG
+       FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+#endif
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+       "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+       "FLAC__STREAM_DECODER_READ_METADATA",
+       "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+       "FLAC__STREAM_DECODER_READ_FRAME",
+       "FLAC__STREAM_DECODER_END_OF_STREAM",
+       "FLAC__STREAM_DECODER_OGG_ERROR",
+       "FLAC__STREAM_DECODER_SEEK_ERROR",
+       "FLAC__STREAM_DECODER_ABORTED",
+       "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+       "FLAC__STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = {
+       "FLAC__STREAM_DECODER_INIT_STATUS_OK",
+       "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+       "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS",
+       "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR",
+       "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE",
+       "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API 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"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = {
+       "FLAC__STREAM_DECODER_SEEK_STATUS_OK",
+       "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR",
+       "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = {
+       "FLAC__STREAM_DECODER_TELL_STATUS_OK",
+       "FLAC__STREAM_DECODER_TELL_STATUS_ERROR",
+       "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = {
+       "FLAC__STREAM_DECODER_LENGTH_STATUS_OK",
+       "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR",
+       "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
+       "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
+       "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
+};
+
+FLAC_API 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",
+       "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+       FLAC__StreamDecoder *decoder;
+       unsigned i;
+
+       FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+       decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
+       if(decoder == 0) {
+               return 0;
+       }
+
+       decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
+       if(decoder->protected_ == 0) {
+               free(decoder);
+               return 0;
+       }
+
+       decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+       if(decoder->private_ == 0) {
+               free(decoder->protected_);
+               free(decoder);
+               return 0;
+       }
+
+       decoder->private_->input = FLAC__bitreader_new();
+       if(decoder->private_->input == 0) {
+               free(decoder->private_);
+               free(decoder->protected_);
+               free(decoder);
+               return 0;
+       }
+
+       decoder->private_->metadata_filter_ids_capacity = 16;
+       if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+               FLAC__bitreader_delete(decoder->private_->input);
+               free(decoder->private_);
+               free(decoder->protected_);
+               free(decoder);
+               return 0;
+       }
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               decoder->private_->output[i] = 0;
+               decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+       }
+
+       decoder->private_->output_capacity = 0;
+       decoder->private_->output_channels = 0;
+       decoder->private_->has_seek_table = false;
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+       decoder->private_->file = 0;
+
+       set_defaults_(decoder);
+
+       decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+       return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->private_->input);
+
+       (void)FLAC__stream_decoder_finish(decoder);
+
+       if(0 != decoder->private_->metadata_filter_ids)
+               free(decoder->private_->metadata_filter_ids);
+
+       FLAC__bitreader_delete(decoder->private_->input);
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
+
+       free(decoder->private_);
+       free(decoder->protected_);
+       free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamDecoderInitStatus init_stream_internal_(
+       FLAC__StreamDecoder *decoder,
+       FLAC__StreamDecoderReadCallback read_callback,
+       FLAC__StreamDecoderSeekCallback seek_callback,
+       FLAC__StreamDecoderTellCallback tell_callback,
+       FLAC__StreamDecoderLengthCallback length_callback,
+       FLAC__StreamDecoderEofCallback eof_callback,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       FLAC__ASSERT(0 != decoder);
+
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+#if !FLAC__HAS_OGG
+       if(is_ogg)
+               return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
+
+       if(
+               0 == read_callback ||
+               0 == write_callback ||
+               0 == error_callback ||
+               (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback))
+       )
+               return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+#if FLAC__HAS_OGG
+       decoder->private_->is_ogg = is_ogg;
+       if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect))
+               return decoder->protected_->state = FLAC__STREAM_DECODER_OGG_ERROR;
+#endif
+
+       /*
+        * get the CPU info and set the function pointers
+        */
+       FLAC__cpu_info(&decoder->private_->cpuinfo);
+       /* first default to the non-asm routines */
+       decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+       decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+       decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+       decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal;
+       decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block;
+       /* now override with asm where appropriate */
+#ifndef FLAC__NO_ASM
+       if(decoder->private_->cpuinfo.use_asm) {
+#ifdef FLAC__CPU_IA32
+               FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#ifdef FLAC__HAS_NASM
+#if 1 /*@@@@@@ OPT: not clearly faster, needs more testing */
+               if(decoder->private_->cpuinfo.data.ia32.bswap)
+                       decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap;
+#endif
+               if(decoder->private_->cpuinfo.data.ia32.mmx) {
+                       decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+                       decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx;
+                       decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx;
+               }
+               else {
+                       decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+                       decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32;
+                       decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32;
+               }
+#endif
+#elif defined FLAC__CPU_PPC
+               FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC);
+               if(decoder->private_->cpuinfo.data.ppc.altivec) {
+                       decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16;
+                       decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8;
+               }
+#endif
+       }
+#endif
+
+       /* from here on, errors are fatal */
+
+       if(!FLAC__bitreader_init(decoder->private_->input, decoder->private_->cpuinfo, read_callback_, decoder)) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+       }
+
+       decoder->private_->read_callback = read_callback;
+       decoder->private_->seek_callback = seek_callback;
+       decoder->private_->tell_callback = tell_callback;
+       decoder->private_->length_callback = length_callback;
+       decoder->private_->eof_callback = eof_callback;
+       decoder->private_->write_callback = write_callback;
+       decoder->private_->metadata_callback = metadata_callback;
+       decoder->private_->error_callback = error_callback;
+       decoder->private_->client_data = client_data;
+       decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+       decoder->private_->samples_decoded = 0;
+       decoder->private_->has_stream_info = false;
+       decoder->private_->cached = false;
+
+       decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+       decoder->private_->is_seeking = false;
+
+       decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */
+       if(!FLAC__stream_decoder_reset(decoder)) {
+               /* above call sets the state for us */
+               return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+       }
+
+       return FLAC__STREAM_DECODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+       FLAC__StreamDecoder *decoder,
+       FLAC__StreamDecoderReadCallback read_callback,
+       FLAC__StreamDecoderSeekCallback seek_callback,
+       FLAC__StreamDecoderTellCallback tell_callback,
+       FLAC__StreamDecoderLengthCallback length_callback,
+       FLAC__StreamDecoderEofCallback eof_callback,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_stream_internal_(
+               decoder,
+               read_callback,
+               seek_callback,
+               tell_callback,
+               length_callback,
+               eof_callback,
+               write_callback,
+               metadata_callback,
+               error_callback,
+               client_data,
+               /*is_ogg=*/false
+       );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+       FLAC__StreamDecoder *decoder,
+       FLAC__StreamDecoderReadCallback read_callback,
+       FLAC__StreamDecoderSeekCallback seek_callback,
+       FLAC__StreamDecoderTellCallback tell_callback,
+       FLAC__StreamDecoderLengthCallback length_callback,
+       FLAC__StreamDecoderEofCallback eof_callback,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_stream_internal_(
+               decoder,
+               read_callback,
+               seek_callback,
+               tell_callback,
+               length_callback,
+               eof_callback,
+               write_callback,
+               metadata_callback,
+               error_callback,
+               client_data,
+               /*is_ogg=*/true
+       );
+}
+
+static FLAC__StreamDecoderInitStatus init_FILE_internal_(
+       FLAC__StreamDecoder *decoder,
+       FILE *file,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != file);
+
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+       if(0 == write_callback || 0 == error_callback)
+               return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+       /*
+        * To make sure that our file does not go unclosed after an error, we
+        * must assign the FILE pointer before any further error can occur in
+        * this routine.
+        */
+       if(file == stdin)
+               file = get_binary_stdin_(); /* just to be safe */
+
+       decoder->private_->file = file;
+
+       return init_stream_internal_(
+               decoder,
+               file_read_callback_,
+               decoder->private_->file == stdin? 0: file_seek_callback_,
+               decoder->private_->file == stdin? 0: file_tell_callback_,
+               decoder->private_->file == stdin? 0: file_length_callback_,
+               file_eof_callback_,
+               write_callback,
+               metadata_callback,
+               error_callback,
+               client_data,
+               is_ogg
+       );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+       FLAC__StreamDecoder *decoder,
+       FILE *file,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+       FLAC__StreamDecoder *decoder,
+       FILE *file,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamDecoderInitStatus init_file_internal_(
+       FLAC__StreamDecoder *decoder,
+       const char *filename,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       FILE *file;
+
+       FLAC__ASSERT(0 != decoder);
+
+       /*
+        * To make sure that our file does not go unclosed after an error, we
+        * have to do the same entrance checks here that are later performed
+        * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned.
+        */
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+       if(0 == write_callback || 0 == error_callback)
+               return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+       file = filename? fopen(filename, "rb") : stdin;
+
+       if(0 == file)
+               return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+
+       return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+       FLAC__StreamDecoder *decoder,
+       const char *filename,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+       FLAC__StreamDecoder *decoder,
+       const char *filename,
+       FLAC__StreamDecoderWriteCallback write_callback,
+       FLAC__StreamDecoderMetadataCallback metadata_callback,
+       FLAC__StreamDecoderErrorCallback error_callback,
+       void *client_data
+)
+{
+       return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool md5_failed = false;
+       unsigned i;
+
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+               return true;
+
+       /* see the comment in FLAC__seekable_stream_decoder_reset() as to why we
+        * always call FLAC__MD5Final()
+        */
+       FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+       if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) {
+               free(decoder->private_->seek_table.data.seek_table.points);
+               decoder->private_->seek_table.data.seek_table.points = 0;
+               decoder->private_->has_seek_table = false;
+       }
+       FLAC__bitreader_free(decoder->private_->input);
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               /* WATCHOUT:
+                * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+                * output arrays have a buffer of up to 3 zeroes in front
+                * (at negative indices) for alignment purposes; we use 4
+                * to keep the data well-aligned.
+                */
+               if(0 != decoder->private_->output[i]) {
+                       free(decoder->private_->output[i]-4);
+                       decoder->private_->output[i] = 0;
+               }
+               if(0 != decoder->private_->residual_unaligned[i]) {
+                       free(decoder->private_->residual_unaligned[i]);
+                       decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+               }
+       }
+       decoder->private_->output_capacity = 0;
+       decoder->private_->output_channels = 0;
+
+#if FLAC__HAS_OGG
+       if(decoder->private_->is_ogg)
+               FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+       if(0 != decoder->private_->file) {
+               if(decoder->private_->file != stdin)
+                       fclose(decoder->private_->file);
+               decoder->private_->file = 0;
+       }
+
+       if(decoder->private_->do_md5_checking) {
+               if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16))
+                       md5_failed = true;
+       }
+       decoder->private_->is_seeking = false;
+
+       set_defaults_(decoder);
+
+       decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+       return !md5_failed;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+#if FLAC__HAS_OGG
+       /* can't check decoder->private_->is_ogg since that's not set until init time */
+       FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value);
+       return true;
+#else
+       (void)value;
+       return false;
+#endif
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       decoder->protected_->md5_checking = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+       /* double protection */
+       if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+               return false;
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       decoder->private_->metadata_filter[type] = true;
+       if(type == FLAC__METADATA_TYPE_APPLICATION)
+               decoder->private_->metadata_filter_ids_count = 0;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       FLAC__ASSERT(0 != id);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+
+       if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+               return true;
+
+       FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+       if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+               if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               decoder->private_->metadata_filter_ids_capacity *= 2;
+       }
+
+       memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+       decoder->private_->metadata_filter_ids_count++;
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+       unsigned i;
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+               decoder->private_->metadata_filter[i] = true;
+       decoder->private_->metadata_filter_ids_count = 0;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+       /* double protection */
+       if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+               return false;
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       decoder->private_->metadata_filter[type] = false;
+       if(type == FLAC__METADATA_TYPE_APPLICATION)
+               decoder->private_->metadata_filter_ids_count = 0;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       FLAC__ASSERT(0 != id);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+
+       if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+               return true;
+
+       FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+       if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+               if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               decoder->private_->metadata_filter_ids_capacity *= 2;
+       }
+
+       memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+       decoder->private_->metadata_filter_ids_count++;
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+       decoder->private_->metadata_filter_ids_count = 0;
+       return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+       return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->md5_checking;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->channel_assignment;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+       return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != position);
+
+#if FLAC__HAS_OGG
+       if(decoder->private_->is_ogg)
+               return false;
+#endif
+       if(0 == decoder->private_->tell_callback)
+               return false;
+       if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK)
+               return false;
+       /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */
+       if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input))
+               return false;
+       FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder));
+       *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder);
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       decoder->private_->samples_decoded = 0;
+       decoder->private_->do_md5_checking = false;
+
+#if FLAC__HAS_OGG
+       if(decoder->private_->is_ogg)
+               FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+       if(!FLAC__bitreader_clear(decoder->private_->input)) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       if(!FLAC__stream_decoder_flush(decoder)) {
+               /* above call sets the state for us */
+               return false;
+       }
+
+#if FLAC__HAS_OGG
+       /*@@@ could go in !internal_reset_hack block below */
+       if(decoder->private_->is_ogg)
+               FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+       /* Rewind if necessary.  If FLAC__stream_decoder_init() is calling us,
+        * (internal_reset_hack) don't try to rewind since we are already at
+        * the beginning of the stream and don't want to fail if the input is
+        * not seekable.
+        */
+       if(!decoder->private_->internal_reset_hack) {
+               if(decoder->private_->file == stdin)
+                       return false; /* can't rewind stdin, reset fails */
+               if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
+                       return false; /* seekable and seek fails, reset fails */
+       }
+       else
+               decoder->private_->internal_reset_hack = false;
+
+       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+       decoder->private_->has_stream_info = false;
+       if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) {
+               free(decoder->private_->seek_table.data.seek_table.points);
+               decoder->private_->seek_table.data.seek_table.points = 0;
+               decoder->private_->has_seek_table = false;
+       }
+       decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+       /*
+        * This goes in reset() and not flush() because according to the spec, a
+        * fixed-blocksize stream must stay that way through the whole stream.
+        */
+       decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+
+       /* We initialize the FLAC__MD5Context even though we may never use it.  This
+        * is because md5 checking may be turned on to start and then turned off if
+        * a seek occurs.  So we init the context here and finalize it in
+        * FLAC__stream_decoder_finish() to make sure things are always cleaned up
+        * properly.
+        */
+       FLAC__MD5Init(&decoder->private_->md5context);
+
+       decoder->private_->first_frame_offset = 0;
+       decoder->private_->unparseable_frame_count = 0;
+
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool got_a_frame;
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       while(1) {
+               switch(decoder->protected_->state) {
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+                               if(!find_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_METADATA:
+                               if(!read_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               else
+                                       return true;
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+                               if(!frame_sync_(decoder))
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_FRAME:
+                               if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+                                       return false; /* above function sets the status for us */
+                               if(got_a_frame)
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_END_OF_STREAM:
+                       case FLAC__STREAM_DECODER_ABORTED:
+                               return true;
+                       default:
+                               FLAC__ASSERT(0);
+                               return false;
+               }
+       }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       while(1) {
+               switch(decoder->protected_->state) {
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+                               if(!find_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_METADATA:
+                               if(!read_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+                       case FLAC__STREAM_DECODER_READ_FRAME:
+                       case FLAC__STREAM_DECODER_END_OF_STREAM:
+                       case FLAC__STREAM_DECODER_ABORTED:
+                               return true;
+                       default:
+                               FLAC__ASSERT(0);
+                               return false;
+               }
+       }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool dummy;
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       while(1) {
+               switch(decoder->protected_->state) {
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+                               if(!find_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_METADATA:
+                               if(!read_metadata_(decoder))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+                               if(!frame_sync_(decoder))
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_FRAME:
+                               if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+                                       return false; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_END_OF_STREAM:
+                       case FLAC__STREAM_DECODER_ABORTED:
+                               return true;
+                       default:
+                               FLAC__ASSERT(0);
+                               return false;
+               }
+       }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool got_a_frame;
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       while(1) {
+               switch(decoder->protected_->state) {
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+                       case FLAC__STREAM_DECODER_READ_METADATA:
+                               return false; /* above function sets the status for us */
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+                               if(!frame_sync_(decoder))
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_FRAME:
+                               if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+                                       return false; /* above function sets the status for us */
+                               if(got_a_frame)
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_END_OF_STREAM:
+                       case FLAC__STREAM_DECODER_ABORTED:
+                               return true;
+                       default:
+                               FLAC__ASSERT(0);
+                               return false;
+               }
+       }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
+{
+       FLAC__uint64 length;
+
+       FLAC__ASSERT(0 != decoder);
+
+       if(
+               decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
+               decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
+               decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+               decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
+               decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
+       )
+               return false;
+
+       if(0 == decoder->private_->seek_callback)
+               return false;
+
+       FLAC__ASSERT(decoder->private_->seek_callback);
+       FLAC__ASSERT(decoder->private_->tell_callback);
+       FLAC__ASSERT(decoder->private_->length_callback);
+       FLAC__ASSERT(decoder->private_->eof_callback);
+
+       if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
+               return false;
+
+       decoder->private_->is_seeking = true;
+
+       /* turn off md5 checking if a seek is attempted */
+       decoder->private_->do_md5_checking = false;
+
+       /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
+       if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
+               decoder->private_->is_seeking = false;
+               return false;
+       }
+
+       /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
+       if(
+               decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
+               decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
+       ) {
+               if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+                       /* above call sets the state for us */
+                       decoder->private_->is_seeking = false;
+                       return false;
+               }
+               /* check this again in case we didn't know total_samples the first time */
+               if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
+                       decoder->private_->is_seeking = false;
+                       return false;
+               }
+       }
+
+       {
+               const FLAC__bool ok =
+#if FLAC__HAS_OGG
+                       decoder->private_->is_ogg?
+                       seek_to_absolute_sample_ogg_(decoder, length, sample) :
+#endif
+                       seek_to_absolute_sample_(decoder, length, sample)
+               ;
+               decoder->private_->is_seeking = false;
+               return ok;
+       }
+}
+
+/***********************************************************************
+ *
+ * Protected class methods
+ *
+ ***********************************************************************/
+
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+       FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7));
+       return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+#if FLAC__HAS_OGG
+       decoder->private_->is_ogg = false;
+#endif
+       decoder->private_->read_callback = 0;
+       decoder->private_->seek_callback = 0;
+       decoder->private_->tell_callback = 0;
+       decoder->private_->length_callback = 0;
+       decoder->private_->eof_callback = 0;
+       decoder->private_->write_callback = 0;
+       decoder->private_->metadata_callback = 0;
+       decoder->private_->error_callback = 0;
+       decoder->private_->client_data = 0;
+
+       memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+       decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
+       decoder->private_->metadata_filter_ids_count = 0;
+
+       decoder->protected_->md5_checking = false;
+
+#if FLAC__HAS_OGG
+       FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect);
+#endif
+}
+
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_(void)
+{
+       /* if something breaks here it is probably due to the presence or
+        * absence of an underscore before the identifiers 'setmode',
+        * 'fileno', and/or 'O_BINARY'; check your system header files.
+        */
+#if defined _MSC_VER || defined __MINGW32__
+       _setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__ 
+       /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+       setmode(_fileno(stdin), _O_BINARY);
+#elif defined __EMX__
+       setmode(fileno(stdin), O_BINARY);
+#endif
+
+       return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
+{
+       unsigned i;
+       FLAC__int32 *tmp;
+
+       if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+               return true;
+
+       /* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               if(0 != decoder->private_->output[i]) {
+                       free(decoder->private_->output[i]-4);
+                       decoder->private_->output[i] = 0;
+               }
+               if(0 != decoder->private_->residual_unaligned[i]) {
+                       free(decoder->private_->residual_unaligned[i]);
+                       decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+               }
+       }
+
+       for(i = 0; i < channels; i++) {
+               /* WATCHOUT:
+                * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+                * output arrays have a buffer of up to 3 zeroes in front
+                * (at negative indices) for alignment purposes; we use 4
+                * to keep the data well-aligned.
+                */
+               tmp = (FLAC__int32*)safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
+               if(tmp == 0) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               memset(tmp, 0, sizeof(FLAC__int32)*4);
+               decoder->private_->output[i] = tmp + 4;
+
+               /* WATCHOUT:
+                * minimum of quadword alignment for PPC vector optimizations is REQUIRED:
+                */
+               if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+       }
+
+       decoder->private_->output_capacity = size;
+       decoder->private_->output_channels = channels;
+
+       return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+       size_t i;
+
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+
+       for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+               if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+                       return true;
+
+       return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+       FLAC__uint32 x;
+       unsigned i, id;
+       FLAC__bool first = true;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       for(i = id = 0; i < 4; ) {
+               if(decoder->private_->cached) {
+                       x = (FLAC__uint32)decoder->private_->lookahead;
+                       decoder->private_->cached = false;
+               }
+               else {
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                               return false; /* read_callback_ sets the state for us */
+               }
+               if(x == FLAC__STREAM_SYNC_STRING[i]) {
+                       first = true;
+                       i++;
+                       id = 0;
+                       continue;
+               }
+               if(x == ID3V2_TAG_[id]) {
+                       id++;
+                       i = 0;
+                       if(id == 3) {
+                               if(!skip_id3v2_tag_(decoder))
+                                       return false; /* skip_id3v2_tag_ sets the state for us */
+                       }
+                       continue;
+               }
+               id = 0;
+               if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+                       decoder->private_->header_warmup[0] = (FLAC__byte)x;
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                               return false; /* read_callback_ sets the state for us */
+
+                       /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+                       /* else we have to check if the second byte is the end of a sync code */
+                       if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+                               decoder->private_->lookahead = (FLAC__byte)x;
+                               decoder->private_->cached = true;
+                       }
+                       else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+                               decoder->private_->header_warmup[1] = (FLAC__byte)x;
+                               decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+                               return true;
+                       }
+               }
+               i = 0;
+               if(first) {
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+                       first = false;
+               }
+       }
+
+       decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+       return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool is_last;
+       FLAC__uint32 i, x, type, length;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN))
+               return false; /* read_callback_ sets the state for us */
+       is_last = x? true : false;
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       if(type == FLAC__METADATA_TYPE_STREAMINFO) {
+               if(!read_metadata_streaminfo_(decoder, is_last, length))
+                       return false;
+
+               decoder->private_->has_stream_info = true;
+               if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+                       decoder->private_->do_md5_checking = false;
+               if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback)
+                       decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
+       }
+       else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+               if(!read_metadata_seektable_(decoder, is_last, length))
+                       return false;
+
+               decoder->private_->has_seek_table = true;
+               if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback)
+                       decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
+       }
+       else {
+               FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+               unsigned real_length = length;
+               FLAC__StreamMetadata block;
+
+               block.is_last = is_last;
+               block.type = (FLAC__MetadataType)type;
+               block.length = length;
+
+               if(type == FLAC__METADATA_TYPE_APPLICATION) {
+                       if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+                               return false; /* read_callback_ sets the state for us */
+
+                       if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */
+                               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/
+                               return false;
+                       }
+
+                       real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+
+                       if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
+                               skip_it = !skip_it;
+               }
+
+               if(skip_it) {
+                       if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+                               return false; /* read_callback_ sets the state for us */
+               }
+               else {
+                       switch(type) {
+                               case FLAC__METADATA_TYPE_PADDING:
+                                       /* skip the padding bytes */
+                                       if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+                                               return false; /* read_callback_ sets the state for us */
+                                       break;
+                               case FLAC__METADATA_TYPE_APPLICATION:
+                                       /* remember, we read the ID already */
+                                       if(real_length > 0) {
+                                               if(0 == (block.data.application.data = (FLAC__byte*)malloc(real_length))) {
+                                                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                                                       return false;
+                                               }
+                                               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+                                                       return false; /* read_callback_ sets the state for us */
+                                       }
+                                       else
+                                               block.data.application.data = 0;
+                                       break;
+                               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                                       if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment))
+                                               return false;
+                                       break;
+                               case FLAC__METADATA_TYPE_CUESHEET:
+                                       if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+                                               return false;
+                                       break;
+                               case FLAC__METADATA_TYPE_PICTURE:
+                                       if(!read_metadata_picture_(decoder, &block.data.picture))
+                                               return false;
+                                       break;
+                               case FLAC__METADATA_TYPE_STREAMINFO:
+                               case FLAC__METADATA_TYPE_SEEKTABLE:
+                                       FLAC__ASSERT(0);
+                                       break;
+                               default:
+                                       if(real_length > 0) {
+                                               if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) {
+                                                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                                                       return false;
+                                               }
+                                               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+                                                       return false; /* read_callback_ sets the state for us */
+                                       }
+                                       else
+                                               block.data.unknown.data = 0;
+                                       break;
+                       }
+                       if(!decoder->private_->is_seeking && decoder->private_->metadata_callback)
+                               decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+
+                       /* now we have to free any malloc()ed data in the block */
+                       switch(type) {
+                               case FLAC__METADATA_TYPE_PADDING:
+                                       break;
+                               case FLAC__METADATA_TYPE_APPLICATION:
+                                       if(0 != block.data.application.data)
+                                               free(block.data.application.data);
+                                       break;
+                               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                                       if(0 != block.data.vorbis_comment.vendor_string.entry)
+                                               free(block.data.vorbis_comment.vendor_string.entry);
+                                       if(block.data.vorbis_comment.num_comments > 0)
+                                               for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+                                                       if(0 != block.data.vorbis_comment.comments[i].entry)
+                                                               free(block.data.vorbis_comment.comments[i].entry);
+                                       if(0 != block.data.vorbis_comment.comments)
+                                               free(block.data.vorbis_comment.comments);
+                                       break;
+                               case FLAC__METADATA_TYPE_CUESHEET:
+                                       if(block.data.cue_sheet.num_tracks > 0)
+                                               for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+                                                       if(0 != block.data.cue_sheet.tracks[i].indices)
+                                                               free(block.data.cue_sheet.tracks[i].indices);
+                                       if(0 != block.data.cue_sheet.tracks)
+                                               free(block.data.cue_sheet.tracks);
+                                       break;
+                               case FLAC__METADATA_TYPE_PICTURE:
+                                       if(0 != block.data.picture.mime_type)
+                                               free(block.data.picture.mime_type);
+                                       if(0 != block.data.picture.description)
+                                               free(block.data.picture.description);
+                                       if(0 != block.data.picture.data)
+                                               free(block.data.picture.data);
+                                       break;
+                               case FLAC__METADATA_TYPE_STREAMINFO:
+                               case FLAC__METADATA_TYPE_SEEKTABLE:
+                                       FLAC__ASSERT(0);
+                               default:
+                                       if(0 != block.data.unknown.data)
+                                               free(block.data.unknown.data);
+                                       break;
+                       }
+               }
+       }
+
+       if(is_last) {
+               /* if this fails, it's OK, it's just a hint for the seek routine */
+               if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset))
+                       decoder->private_->first_frame_offset = 0;
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+       }
+
+       return true;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+       FLAC__uint32 x;
+       unsigned bits, used_bits = 0;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
+       decoder->private_->stream_info.is_last = is_last;
+       decoder->private_->stream_info.length = length;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.min_blocksize = x;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.max_blocksize = x;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.min_framesize = x;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.max_framesize = x;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.sample_rate = x;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.channels = x+1;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN;
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1;
+       used_bits += bits;
+
+       bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN;
+       if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+               return false; /* read_callback_ sets the state for us */
+       used_bits += bits;
+
+       if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16))
+               return false; /* read_callback_ sets the state for us */
+       used_bits += 16*8;
+
+       /* skip the rest of the block */
+       FLAC__ASSERT(used_bits % 8 == 0);
+       length -= (used_bits / 8);
+       if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+               return false; /* read_callback_ sets the state for us */
+
+       return true;
+}
+
+FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+       FLAC__uint32 i, x;
+       FLAC__uint64 xx;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
+       decoder->private_->seek_table.is_last = is_last;
+       decoder->private_->seek_table.length = length;
+
+       decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+       /* use realloc since we may pass through here several times (e.g. after seeking) */
+       if(0 == (decoder->private_->seek_table.data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) {
+               if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+                       return false; /* read_callback_ sets the state for us */
+               decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx;
+
+               if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+                       return false; /* read_callback_ sets the state for us */
+               decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx;
+
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+                       return false; /* read_callback_ sets the state for us */
+               decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x;
+       }
+       length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH);
+       /* if there is a partial point left, skip over it */
+       if(length > 0) {
+               /*@@@ do a send_error_to_client_() here?  there's an argument for either way */
+               if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+                       return false; /* read_callback_ sets the state for us */
+       }
+
+       return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj)
+{
+       FLAC__uint32 i;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       /* read vendor string */
+       FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+       if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
+               return false; /* read_callback_ sets the state for us */
+       if(obj->vendor_string.length > 0) {
+               if(0 == (obj->vendor_string.entry = (FLAC__byte*)safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
+                       return false; /* read_callback_ sets the state for us */
+               obj->vendor_string.entry[obj->vendor_string.length] = '\0';
+       }
+       else
+               obj->vendor_string.entry = 0;
+
+       /* read num comments */
+       FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32);
+       if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
+               return false; /* read_callback_ sets the state for us */
+
+       /* read comments */
+       if(obj->num_comments > 0) {
+               if(0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)safe_malloc_mul_2op_(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               for(i = 0; i < obj->num_comments; i++) {
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+                       if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length))
+                               return false; /* read_callback_ sets the state for us */
+                       if(obj->comments[i].length > 0) {
+                               if(0 == (obj->comments[i].entry = (FLAC__byte*)safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
+                                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                                       return false;
+                               }
+                               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length))
+                                       return false; /* read_callback_ sets the state for us */
+                               obj->comments[i].entry[obj->comments[i].length] = '\0';
+                       }
+                       else
+                               obj->comments[i].entry = 0;
+               }
+       }
+       else {
+               obj->comments = 0;
+       }
+
+       return true;
+}
+
+FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+       FLAC__uint32 i, j, x;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet));
+
+       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+       if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+               return false; /* read_callback_ sets the state for us */
+
+       if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+               return false; /* read_callback_ sets the state for us */
+       obj->is_cd = x? true : false;
+
+       if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+               return false; /* read_callback_ sets the state for us */
+       obj->num_tracks = x;
+
+       if(obj->num_tracks > 0) {
+               if(0 == (obj->tracks = (FLAC__StreamMetadata_CueSheet_Track*)safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                       return false;
+               }
+               for(i = 0; i < obj->num_tracks; i++) {
+                       FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i];
+                       if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+                               return false; /* read_callback_ sets the state for us */
+
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       track->number = (FLAC__byte)x;
+
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+                       if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+                               return false; /* read_callback_ sets the state for us */
+
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       track->type = x;
+
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       track->pre_emphasis = x;
+
+                       if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+                               return false; /* read_callback_ sets the state for us */
+
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       track->num_indices = (FLAC__byte)x;
+
+                       if(track->num_indices > 0) {
+                               if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) {
+                                       decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+                                       return false;
+                               }
+                               for(j = 0; j < track->num_indices; j++) {
+                                       FLAC__StreamMetadata_CueSheet_Index *index = &track->indices[j];
+                                       if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+                                               return false; /* read_callback_ sets the state for us */
+
+                                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+                                               return false; /* read_callback_ sets the state for us */
+                                       index->number = (FLAC__byte)x;
+
+                                       if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+                                               return false; /* read_callback_ sets the state for us */
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+       FLAC__uint32 x;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       /* read type */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       obj->type = x;
+
+       /* read MIME type */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+       if(0 == (obj->mime_type = (char*)safe_malloc_add_2op_(x, /*+*/1))) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       if(x > 0) {
+               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x))
+                       return false; /* read_callback_ sets the state for us */
+       }
+       obj->mime_type[x] = '\0';
+
+       /* read description */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+       if(0 == (obj->description = (FLAC__byte*)safe_malloc_add_2op_(x, /*+*/1))) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       if(x > 0) {
+               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x))
+                       return false; /* read_callback_ sets the state for us */
+       }
+       obj->description[x] = '\0';
+
+       /* read width */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       /* read height */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       /* read depth */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       /* read colors */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+               return false; /* read_callback_ sets the state for us */
+
+       /* read data */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+               return false; /* read_callback_ sets the state for us */
+       if(0 == (obj->data = (FLAC__byte*)safe_malloc_(obj->data_length))) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+       if(obj->data_length > 0) {
+               if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length))
+                       return false; /* read_callback_ sets the state for us */
+       }
+
+       return true;
+}
+
+FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+       FLAC__uint32 x;
+       unsigned i, skip;
+
+       /* skip the version and flags bytes */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24))
+               return false; /* read_callback_ sets the state for us */
+       /* get the size (in bytes) to skip */
+       skip = 0;
+       for(i = 0; i < 4; i++) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                       return false; /* read_callback_ sets the state for us */
+               skip <<= 7;
+               skip |= (x & 0x7f);
+       }
+       /* skip the rest of the tag */
+       if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+               return false; /* read_callback_ sets the state for us */
+       return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+       FLAC__uint32 x;
+       FLAC__bool first = true;
+
+       /* If we know the total number of samples in the stream, stop if we've read that many. */
+       /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+       if(FLAC__stream_decoder_get_total_samples(decoder) > 0) {
+               if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+                       return true;
+               }
+       }
+
+       /* make sure we're byte aligned */
+       if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+                       return false; /* read_callback_ sets the state for us */
+       }
+
+       while(1) {
+               if(decoder->private_->cached) {
+                       x = (FLAC__uint32)decoder->private_->lookahead;
+                       decoder->private_->cached = false;
+               }
+               else {
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                               return false; /* read_callback_ sets the state for us */
+               }
+               if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+                       decoder->private_->header_warmup[0] = (FLAC__byte)x;
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                               return false; /* read_callback_ sets the state for us */
+
+                       /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+                       /* else we have to check if the second byte is the end of a sync code */
+                       if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+                               decoder->private_->lookahead = (FLAC__byte)x;
+                               decoder->private_->cached = true;
+                       }
+                       else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+                               decoder->private_->header_warmup[1] = (FLAC__byte)x;
+                               decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+                               return true;
+                       }
+               }
+               if(first) {
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+                       first = false;
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+       unsigned channel;
+       unsigned i;
+       FLAC__int32 mid, side;
+       unsigned frame_crc; /* the one we calculate from the input stream */
+       FLAC__uint32 x;
+
+       *got_a_frame = false;
+
+       /* init the CRC */
+       frame_crc = 0;
+       frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+       frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+       FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc);
+
+       if(!read_frame_header_(decoder))
+               return false;
+       if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */
+               return true;
+       if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
+               return false;
+       for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+               /*
+                * first figure the correct bits-per-sample of the subframe
+                */
+               unsigned bps = decoder->private_->frame.header.bits_per_sample;
+               switch(decoder->private_->frame.header.channel_assignment) {
+                       case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                               /* no adjustment needed */
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                               if(channel == 1)
+                                       bps++;
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                               if(channel == 0)
+                                       bps++;
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                               if(channel == 1)
+                                       bps++;
+                               break;
+                       default:
+                               FLAC__ASSERT(0);
+               }
+               /*
+                * now read it
+                */
+               if(!read_subframe_(decoder, channel, bps, do_full_decode))
+                       return false;
+               if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+                       return true;
+       }
+       if(!read_zero_padding_(decoder))
+               return false;
+       if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */
+               return true;
+
+       /*
+        * Read the frame CRC-16 from the footer and check
+        */
+       frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input);
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN))
+               return false; /* read_callback_ sets the state for us */
+       if(frame_crc == x) {
+               if(do_full_decode) {
+                       /* Undo any special channel coding */
+                       switch(decoder->private_->frame.header.channel_assignment) {
+                               case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                                       /* do nothing */
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                                               decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                                               decoder->private_->output[0][i] += decoder->private_->output[1][i];
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+#if 1
+                                               mid = decoder->private_->output[0][i];
+                                               side = decoder->private_->output[1][i];
+                                               mid <<= 1;
+                                               mid |= (side & 1); /* i.e. if 'side' is odd... */
+                                               decoder->private_->output[0][i] = (mid + side) >> 1;
+                                               decoder->private_->output[1][i] = (mid - side) >> 1;
+#else
+                                               /* OPT: without 'side' temp variable */
+                                               mid = (decoder->private_->output[0][i] << 1) | (decoder->private_->output[1][i] & 1); /* i.e. if 'side' is odd... */
+                                               decoder->private_->output[0][i] = (mid + decoder->private_->output[1][i]) >> 1;
+                                               decoder->private_->output[1][i] = (mid - decoder->private_->output[1][i]) >> 1;
+#endif
+                                       }
+                                       break;
+                               default:
+                                       FLAC__ASSERT(0);
+                                       break;
+                       }
+               }
+       }
+       else {
+               /* Bad frame, emit error and zero the output signal */
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+               if(do_full_decode) {
+                       for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+                               memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+                       }
+               }
+       }
+
+       *got_a_frame = true;
+
+       /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */
+       if(decoder->private_->next_fixed_block_size)
+               decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size;
+
+       /* put the latest values into the public section of the decoder instance */
+       decoder->protected_->channels = decoder->private_->frame.header.channels;
+       decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment;
+       decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+       decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+       decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+
+       FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+       decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+       /* write it */
+       if(do_full_decode) {
+               if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
+                       return false;
+       }
+
+       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+       return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+       FLAC__uint32 x;
+       FLAC__uint64 xx;
+       unsigned i, blocksize_hint = 0, sample_rate_hint = 0;
+       FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+       unsigned raw_header_len;
+       FLAC__bool is_unparseable = false;
+
+       FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+       /* init the raw header with the saved bits from synchronization */
+       raw_header[0] = decoder->private_->header_warmup[0];
+       raw_header[1] = decoder->private_->header_warmup[1];
+       raw_header_len = 2;
+
+       /* check to make sure that reserved bit is 0 */
+       if(raw_header[1] & 0x02) /* MAGIC NUMBER */
+               is_unparseable = true;
+
+       /*
+        * Note that along the way as we read the header, we look for a sync
+        * code inside.  If we find one it would indicate that our original
+        * sync was bad since there cannot be a sync code in a valid header.
+        *
+        * Three kinds of things can go wrong when reading the frame header:
+        *  1) We may have sync'ed incorrectly and not landed on a frame header.
+        *     If we don't find a sync code, it can end up looking like we read
+        *     a valid but unparseable header, until getting to the frame header
+        *     CRC.  Even then we could get a false positive on the CRC.
+        *  2) We may have sync'ed correctly but on an unparseable frame (from a
+        *     future encoder).
+        *  3) We may be on a damaged frame which appears valid but unparseable.
+        *
+        * For all these reasons, we try and read a complete frame header as
+        * long as it seems valid, even if unparseable, up until the frame
+        * header CRC.
+        */
+
+       /*
+        * read in the raw header as bytes so we can CRC it, and parse it on the way
+        */
+       for(i = 0; i < 2; i++) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                       return false; /* read_callback_ sets the state for us */
+               if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+                       /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+                       decoder->private_->lookahead = (FLAC__byte)x;
+                       decoder->private_->cached = true;
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               }
+               raw_header[raw_header_len++] = (FLAC__byte)x;
+       }
+
+       switch(x = raw_header[2] >> 4) {
+               case 0:
+                       is_unparseable = true;
+                       break;
+               case 1:
+                       decoder->private_->frame.header.blocksize = 192;
+                       break;
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+                       decoder->private_->frame.header.blocksize = 576 << (x-2);
+                       break;
+               case 6:
+               case 7:
+                       blocksize_hint = x;
+                       break;
+               case 8:
+               case 9:
+               case 10:
+               case 11:
+               case 12:
+               case 13:
+               case 14:
+               case 15:
+                       decoder->private_->frame.header.blocksize = 256 << (x-8);
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+                       break;
+       }
+
+       switch(x = raw_header[2] & 0x0f) {
+               case 0:
+                       if(decoder->private_->has_stream_info)
+                               decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+                       else
+                               is_unparseable = true;
+                       break;
+               case 1:
+                       decoder->private_->frame.header.sample_rate = 88200;
+                       break;
+               case 2:
+                       decoder->private_->frame.header.sample_rate = 176400;
+                       break;
+               case 3:
+                       decoder->private_->frame.header.sample_rate = 192000;
+                       break;
+               case 4:
+                       decoder->private_->frame.header.sample_rate = 8000;
+                       break;
+               case 5:
+                       decoder->private_->frame.header.sample_rate = 16000;
+                       break;
+               case 6:
+                       decoder->private_->frame.header.sample_rate = 22050;
+                       break;
+               case 7:
+                       decoder->private_->frame.header.sample_rate = 24000;
+                       break;
+               case 8:
+                       decoder->private_->frame.header.sample_rate = 32000;
+                       break;
+               case 9:
+                       decoder->private_->frame.header.sample_rate = 44100;
+                       break;
+               case 10:
+                       decoder->private_->frame.header.sample_rate = 48000;
+                       break;
+               case 11:
+                       decoder->private_->frame.header.sample_rate = 96000;
+                       break;
+               case 12:
+               case 13:
+               case 14:
+                       sample_rate_hint = x;
+                       break;
+               case 15:
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       x = (unsigned)(raw_header[3] >> 4);
+       if(x & 8) {
+               decoder->private_->frame.header.channels = 2;
+               switch(x & 7) {
+                       case 0:
+                               decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+                               break;
+                       case 1:
+                               decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+                               break;
+                       case 2:
+                               decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+                               break;
+                       default:
+                               is_unparseable = true;
+                               break;
+               }
+       }
+       else {
+               decoder->private_->frame.header.channels = (unsigned)x + 1;
+               decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+       }
+
+       switch(x = (unsigned)(raw_header[3] & 0x0e) >> 1) {
+               case 0:
+                       if(decoder->private_->has_stream_info)
+                               decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+                       else
+                               is_unparseable = true;
+                       break;
+               case 1:
+                       decoder->private_->frame.header.bits_per_sample = 8;
+                       break;
+               case 2:
+                       decoder->private_->frame.header.bits_per_sample = 12;
+                       break;
+               case 4:
+                       decoder->private_->frame.header.bits_per_sample = 16;
+                       break;
+               case 5:
+                       decoder->private_->frame.header.bits_per_sample = 20;
+                       break;
+               case 6:
+                       decoder->private_->frame.header.bits_per_sample = 24;
+                       break;
+               case 3:
+               case 7:
+                       is_unparseable = true;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+                       break;
+       }
+
+       /* check to make sure that reserved bit is 0 */
+       if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+               is_unparseable = true;
+
+       /* read the frame's starting sample number (or frame number as the case may be) */
+       if(
+               raw_header[1] & 0x01 ||
+               /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */
+               (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize)
+       ) { /* variable blocksize */
+               if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len))
+                       return false; /* read_callback_ sets the state for us */
+               if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */
+                       decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+                       decoder->private_->cached = true;
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               }
+               decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+               decoder->private_->frame.header.number.sample_number = xx;
+       }
+       else { /* fixed blocksize */
+               if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len))
+                       return false; /* read_callback_ sets the state for us */
+               if(x == 0xffffffff) { /* i.e. non-UTF8 code... */
+                       decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+                       decoder->private_->cached = true;
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               }
+               decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+               decoder->private_->frame.header.number.frame_number = x;
+       }
+
+       if(blocksize_hint) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                       return false; /* read_callback_ sets the state for us */
+               raw_header[raw_header_len++] = (FLAC__byte)x;
+               if(blocksize_hint == 7) {
+                       FLAC__uint32 _x;
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+                               return false; /* read_callback_ sets the state for us */
+                       raw_header[raw_header_len++] = (FLAC__byte)_x;
+                       x = (x << 8) | _x;
+               }
+               decoder->private_->frame.header.blocksize = x+1;
+       }
+
+       if(sample_rate_hint) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+                       return false; /* read_callback_ sets the state for us */
+               raw_header[raw_header_len++] = (FLAC__byte)x;
+               if(sample_rate_hint != 12) {
+                       FLAC__uint32 _x;
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+                               return false; /* read_callback_ sets the state for us */
+                       raw_header[raw_header_len++] = (FLAC__byte)_x;
+                       x = (x << 8) | _x;
+               }
+               if(sample_rate_hint == 12)
+                       decoder->private_->frame.header.sample_rate = x*1000;
+               else if(sample_rate_hint == 13)
+                       decoder->private_->frame.header.sample_rate = x;
+               else
+                       decoder->private_->frame.header.sample_rate = x*10;
+       }
+
+       /* read the CRC-8 byte */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+               return false; /* read_callback_ sets the state for us */
+       crc8 = (FLAC__byte)x;
+
+       if(FLAC__crc8(raw_header, raw_header_len) != crc8) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+
+       /* calculate the sample number from the frame number if needed */
+       decoder->private_->next_fixed_block_size = 0;
+       if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+               x = decoder->private_->frame.header.number.frame_number;
+               decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+               if(decoder->private_->fixed_block_size)
+                       decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x;
+               else if(decoder->private_->has_stream_info) {
+                       if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) {
+                               decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x;
+                               decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize;
+                       }
+                       else
+                               is_unparseable = true;
+               }
+               else if(x == 0) {
+                       decoder->private_->frame.header.number.sample_number = 0;
+                       decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize;
+               }
+               else {
+                       /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */
+                       decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x;
+               }
+       }
+
+       if(is_unparseable) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+
+       return true;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+       FLAC__uint32 x;
+       FLAC__bool wasted_bits;
+       unsigned i;
+
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */
+               return false; /* read_callback_ sets the state for us */
+
+       wasted_bits = (x & 1);
+       x &= 0xfe;
+
+       if(wasted_bits) {
+               unsigned u;
+               if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u))
+                       return false; /* read_callback_ sets the state for us */
+               decoder->private_->frame.subframes[channel].wasted_bits = u+1;
+               bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+       }
+       else
+               decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+       /*
+        * Lots of magic numbers here
+        */
+       if(x & 0x80) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+       else if(x == 0) {
+               if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+                       return false;
+       }
+       else if(x == 2) {
+               if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+                       return false;
+       }
+       else if(x < 16) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+       else if(x <= 24) {
+               if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
+                       return false;
+               if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+                       return true;
+       }
+       else if(x < 64) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+       else {
+               if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
+                       return false;
+               if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+                       return true;
+       }
+
+       if(wasted_bits && do_full_decode) {
+               x = decoder->private_->frame.subframes[channel].wasted_bits;
+               for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                       decoder->private_->output[channel][i] <<= x;
+       }
+
+       return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+       FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+       FLAC__int32 x;
+       unsigned i;
+       FLAC__int32 *output = decoder->private_->output[channel];
+
+       decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+       if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+               return false; /* read_callback_ sets the state for us */
+
+       subframe->value = x;
+
+       /* decode the subframe */
+       if(do_full_decode) {
+               for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                       output[i] = x;
+       }
+
+       return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+       FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+       FLAC__int32 i32;
+       FLAC__uint32 u32;
+       unsigned u;
+
+       decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+       subframe->residual = decoder->private_->residual[channel];
+       subframe->order = order;
+
+       /* read warm-up samples */
+       for(u = 0; u < order; u++) {
+               if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+                       return false; /* read_callback_ sets the state for us */
+               subframe->warmup[u] = i32;
+       }
+
+       /* read entropy coding method info */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+                       subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+                       break;
+               default:
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+       }
+
+       /* read residual */
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+                               return false;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       /* decode the subframe */
+       if(do_full_decode) {
+               memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+               FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+       }
+
+       return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+       FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+       FLAC__int32 i32;
+       FLAC__uint32 u32;
+       unsigned u;
+
+       decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+       subframe->residual = decoder->private_->residual[channel];
+       subframe->order = order;
+
+       /* read warm-up samples */
+       for(u = 0; u < order; u++) {
+               if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+                       return false; /* read_callback_ sets the state for us */
+               subframe->warmup[u] = i32;
+       }
+
+       /* read qlp coeff precision */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+               return false; /* read_callback_ sets the state for us */
+       if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) {
+               send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+               decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               return true;
+       }
+       subframe->qlp_coeff_precision = u32+1;
+
+       /* read qlp shift */
+       if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+               return false; /* read_callback_ sets the state for us */
+       subframe->quantization_level = i32;
+
+       /* read quantized lp coefficiencts */
+       for(u = 0; u < order; u++) {
+               if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision))
+                       return false; /* read_callback_ sets the state for us */
+               subframe->qlp_coeff[u] = i32;
+       }
+
+       /* read entropy coding method info */
+       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+               return false; /* read_callback_ sets the state for us */
+       subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+                       subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+                       break;
+               default:
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+       }
+
+       /* read residual */
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+                               return false;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       /* decode the subframe */
+       if(do_full_decode) {
+               memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+               /*@@@@@@ technically not pessimistic enough, should be more like
+               if( (FLAC__uint64)order * ((((FLAC__uint64)1)<<bps)-1) * ((1<<subframe->qlp_coeff_precision)-1) < (((FLAC__uint64)-1) << 32) )
+               */
+               if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+                       if(bps <= 16 && subframe->qlp_coeff_precision <= 16) {
+                               if(order <= 8)
+                                       decoder->private_->local_lpc_restore_signal_16bit_order8(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+                               else
+                                       decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+                       }
+                       else
+                               decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+               else
+                       decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+       }
+
+       return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+       FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+       FLAC__int32 x, *residual = decoder->private_->residual[channel];
+       unsigned i;
+
+       decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+       subframe->data = residual;
+
+       for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+               if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+                       return false; /* read_callback_ sets the state for us */
+               residual[i] = x;
+       }
+
+       /* decode the subframe */
+       if(do_full_decode)
+               memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+       return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
+{
+       FLAC__uint32 rice_parameter;
+       int i;
+       unsigned partition, sample, u;
+       const unsigned partitions = 1u << partition_order;
+       const unsigned partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
+       const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+       const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+       /* sanity checks */
+       if(partition_order == 0) {
+               if(decoder->private_->frame.header.blocksize < predictor_order) {
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               }
+       }
+       else {
+               if(partition_samples < predictor_order) {
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+                       return true;
+               }
+       }
+
+       if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order))) {
+               decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       sample = 0;
+       for(partition = 0; partition < partitions; partition++) {
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen))
+                       return false; /* read_callback_ sets the state for us */
+               partitioned_rice_contents->parameters[partition] = rice_parameter;
+               if(rice_parameter < pesc) {
+                       partitioned_rice_contents->raw_bits[partition] = 0;
+                       u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
+                       if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
+                               return false; /* read_callback_ sets the state for us */
+                       sample += u;
+               }
+               else {
+                       if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+                               return false; /* read_callback_ sets the state for us */
+                       partitioned_rice_contents->raw_bits[partition] = rice_parameter;
+                       for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+                               if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+                                       return false; /* read_callback_ sets the state for us */
+                               residual[sample] = i;
+                       }
+               }
+       }
+
+       return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+       if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+               FLAC__uint32 zero = 0;
+               if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+                       return false; /* read_callback_ sets the state for us */
+               if(zero != 0) {
+                       send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+               }
+       }
+       return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+
+       if(
+#if FLAC__HAS_OGG
+               /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+               !decoder->private_->is_ogg &&
+#endif
+               decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+       ) {
+               *bytes = 0;
+               decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+               return false;
+       }
+       else if(*bytes > 0) {
+               /* While seeking, it is possible for our seek to land in the
+                * middle of audio data that looks exactly like a frame header
+                * from a future version of an encoder.  When that happens, our
+                * error callback will get an
+                * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its
+                * unparseable_frame_count.  But there is a remote possibility
+                * that it is properly synced at such a "future-codec frame",
+                * so to make sure, we wait to see many "unparseable" errors in
+                * a row before bailing out.
+                */
+               if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+                       return false;
+               }
+               else {
+                       const FLAC__StreamDecoderReadStatus status =
+#if FLAC__HAS_OGG
+                               decoder->private_->is_ogg?
+                               read_callback_ogg_aspect_(decoder, buffer, bytes) :
+#endif
+                               decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data)
+                       ;
+                       if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) {
+                               decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+                               return false;
+                       }
+                       else if(*bytes == 0) {
+                               if(
+                                       status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM ||
+                                       (
+#if FLAC__HAS_OGG
+                                               /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+                                               !decoder->private_->is_ogg &&
+#endif
+                                               decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+                                       )
+                               ) {
+                                       decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+                                       return false;
+                               }
+                               else
+                                       return true;
+                       }
+                       else
+                               return true;
+               }
+       }
+       else {
+               /* abort to avoid a deadlock */
+               decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+               return false;
+       }
+       /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around
+        * for Ogg FLAC.  This is because the ogg decoder aspect can lose sync
+        * and at the same time hit the end of the stream (for example, seeking
+        * to a point that is after the beginning of the last Ogg page).  There
+        * is no way to report an Ogg sync loss through the callbacks (see note
+        * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0.
+        * So to keep the decoder from stopping at this point we gate the call
+        * to the eof_callback and let the Ogg decoder aspect set the
+        * end-of-stream state when it is needed.
+        */
+}
+
+#if FLAC__HAS_OGG
+FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes)
+{
+       switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) {
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+               /* we don't really have a way to handle lost sync via read
+                * callback so we'll let it pass and let the underlying
+                * FLAC decoder catch the error
+                */
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC:
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+                       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC:
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION:
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR:
+               case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR:
+                       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+               default:
+                       FLAC__ASSERT(0);
+                       /* double protection */
+                       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+       }
+}
+
+FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder;
+
+       switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) {
+               case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE:
+                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+               case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM:
+                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+               case FLAC__STREAM_DECODER_READ_STATUS_ABORT:
+                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+               default:
+                       /* double protection: */
+                       FLAC__ASSERT(0);
+                       return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+       }
+}
+#endif
+
+FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       if(decoder->private_->is_seeking) {
+               FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
+               FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
+               FLAC__uint64 target_sample = decoder->private_->target_sample;
+
+               FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+#if FLAC__HAS_OGG
+               decoder->private_->got_a_frame = true;
+#endif
+               decoder->private_->last_frame = *frame; /* save the frame */
+               if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+                       unsigned delta = (unsigned)(target_sample - this_frame_sample);
+                       /* kick out of seek mode */
+                       decoder->private_->is_seeking = false;
+                       /* shift out the samples before target_sample */
+                       if(delta > 0) {
+                               unsigned channel;
+                               const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
+                               for(channel = 0; channel < frame->header.channels; channel++)
+                                       newbuffer[channel] = buffer[channel] + delta;
+                               decoder->private_->last_frame.header.blocksize -= delta;
+                               decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+                               /* write the relevant samples */
+                               return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data);
+                       }
+                       else {
+                               /* write the relevant samples */
+                               return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+                       }
+               }
+               else {
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+               }
+       }
+       else {
+               /*
+                * If we never got STREAMINFO, turn off MD5 checking to save
+                * cycles since we don't have a sum to compare to anyway
+                */
+               if(!decoder->private_->has_stream_info)
+                       decoder->private_->do_md5_checking = false;
+               if(decoder->private_->do_md5_checking) {
+                       if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
+                               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+               return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+       }
+}
+
+void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status)
+{
+       if(!decoder->private_->is_seeking)
+               decoder->private_->error_callback(decoder, status, decoder->private_->client_data);
+       else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+               decoder->private_->unparseable_frame_count++;
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+       FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
+       FLAC__int64 pos = -1;
+       int i;
+       unsigned approx_bytes_per_frame;
+       FLAC__bool first_seek = true;
+       const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+       const unsigned min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+       const unsigned max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+       const unsigned max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+       const unsigned min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+       /* take these from the current frame in case they've changed mid-stream */
+       unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+       unsigned bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
+       const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;
+
+       /* use values from stream info if we didn't decode a frame */
+       if(channels == 0)
+               channels = decoder->private_->stream_info.data.stream_info.channels;
+       if(bps == 0)
+               bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+
+       /* we are just guessing here */
+       if(max_framesize > 0)
+               approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
+       /*
+        * Check if it's a known fixed-blocksize stream.  Note that though
+        * the spec doesn't allow zeroes in the STREAMINFO block, we may
+        * never get a STREAMINFO block when decoding so the value of
+        * min_blocksize might be zero.
+        */
+       else if(min_blocksize == max_blocksize && min_blocksize > 0) {
+               /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */
+               approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
+       }
+       else
+               approx_bytes_per_frame = 4096 * channels * bps/8 + 64;
+
+       /*
+        * First, we set an upper and lower bound on where in the
+        * stream we will search.  For now we assume the worst case
+        * scenario, which is our best guess at the beginning of
+        * the first frame and end of the stream.
+        */
+       lower_bound = first_frame_offset;
+       lower_bound_sample = 0;
+       upper_bound = stream_length;
+       upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/;
+
+       /*
+        * Now we refine the bounds if we have a seektable with
+        * suitable points.  Note that according to the spec they
+        * must be ordered by ascending sample number.
+        *
+        * Note: to protect against invalid seek tables we will ignore points
+        * that have frame_samples==0 or sample_number>=total_samples
+        */
+       if(seek_table) {
+               FLAC__uint64 new_lower_bound = lower_bound;
+               FLAC__uint64 new_upper_bound = upper_bound;
+               FLAC__uint64 new_lower_bound_sample = lower_bound_sample;
+               FLAC__uint64 new_upper_bound_sample = upper_bound_sample;
+
+               /* find the closest seek point <= target_sample, if it exists */
+               for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
+                       if(
+                               seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+                               seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+                               (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+                               seek_table->points[i].sample_number <= target_sample
+                       )
+                               break;
+               }
+               if(i >= 0) { /* i.e. we found a suitable seek point... */
+                       new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
+                       new_lower_bound_sample = seek_table->points[i].sample_number;
+               }
+
+               /* find the closest seek point > target_sample, if it exists */
+               for(i = 0; i < (int)seek_table->num_points; i++) {
+                       if(
+                               seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+                               seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+                               (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+                               seek_table->points[i].sample_number > target_sample
+                       )
+                               break;
+               }
+               if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
+                       new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
+                       new_upper_bound_sample = seek_table->points[i].sample_number;
+               }
+               /* final protection against unsorted seek tables; keep original values if bogus */
+               if(new_upper_bound >= new_lower_bound) {
+                       lower_bound = new_lower_bound;
+                       upper_bound = new_upper_bound;
+                       lower_bound_sample = new_lower_bound_sample;
+                       upper_bound_sample = new_upper_bound_sample;
+               }
+       }
+
+       FLAC__ASSERT(upper_bound_sample >= lower_bound_sample);
+       /* there are 2 insidious ways that the following equality occurs, which
+        * we need to fix:
+        *  1) total_samples is 0 (unknown) and target_sample is 0
+        *  2) total_samples is 0 (unknown) and target_sample happens to be
+        *     exactly equal to the last seek point in the seek table; this
+        *     means there is no seek point above it, and upper_bound_samples
+        *     remains equal to the estimate (of target_samples) we made above
+        * in either case it does not hurt to move upper_bound_sample up by 1
+        */
+       if(upper_bound_sample == lower_bound_sample)
+               upper_bound_sample++;
+
+       decoder->private_->target_sample = target_sample;
+       while(1) {
+               /* check if the bounds are still ok */
+               if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+               /* with VC++ you have to spoon feed it the casting */
+               pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(FLAC__int64)(target_sample - lower_bound_sample) / (FLAC__double)(FLAC__int64)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(FLAC__int64)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#else
+               pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#endif
+#else
+               /* a little less accurate: */
+               if(upper_bound - lower_bound < 0xffffffff)
+                       pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame;
+               else /* @@@ WATCHOUT, ~2TB limit */
+                       pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame;
+#endif
+               if(pos >= (FLAC__int64)upper_bound)
+                       pos = (FLAC__int64)upper_bound - 1;
+               if(pos < (FLAC__int64)lower_bound)
+                       pos = (FLAC__int64)lower_bound;
+               if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+               if(!FLAC__stream_decoder_flush(decoder)) {
+                       /* above call sets the state for us */
+                       return false;
+               }
+               /* Now we need to get a frame.  First we need to reset our
+                * unparseable_frame_count; if we get too many unparseable
+                * frames in a row, the read callback will return
+                * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+                * FLAC__stream_decoder_process_single() to return false.
+                */
+               decoder->private_->unparseable_frame_count = 0;
+               if(!FLAC__stream_decoder_process_single(decoder)) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+               /* our write callback will change the state when it gets to the target frame */
+               /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
+#if 0
+               /*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */
+               if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
+                       break;
+#endif
+               if(!decoder->private_->is_seeking)
+                       break;
+
+               FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+               this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+
+               if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
+                       if (pos == (FLAC__int64)lower_bound) {
+                               /* can't move back any more than the first frame, something is fatally wrong */
+                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                               return false;
+                       }
+                       /* our last move backwards wasn't big enough, try again */
+                       approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16;
+                       continue;       
+               }
+               /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */
+               first_seek = false;
+               
+               /* make sure we are not seeking in corrupted stream */
+               if (this_frame_sample < lower_bound_sample) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+
+               /* we need to narrow the search */
+               if(target_sample < this_frame_sample) {
+                       upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+/*@@@@@@ what will decode position be if at end of stream? */
+                       if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
+                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                               return false;
+                       }
+                       approx_bytes_per_frame = (unsigned)(2 * (upper_bound - pos) / 3 + 16);
+               }
+               else { /* target_sample >= this_frame_sample + this frame's blocksize */
+                       lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+                       if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
+                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                               return false;
+                       }
+                       approx_bytes_per_frame = (unsigned)(2 * (lower_bound - pos) / 3 + 16);
+               }
+       }
+
+       return true;
+}
+
+#if FLAC__HAS_OGG
+FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+       FLAC__uint64 left_pos = 0, right_pos = stream_length;
+       FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder);
+       FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1;
+       FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */
+       FLAC__bool did_a_seek;
+       unsigned iteration = 0;
+
+       /* In the first iterations, we will calculate the target byte position 
+        * by the distance from the target sample to left_sample and
+        * right_sample (let's call it "proportional search").  After that, we
+        * will switch to binary search.
+        */
+       unsigned BINARY_SEARCH_AFTER_ITERATION = 2;
+
+       /* We will switch to a linear search once our current sample is less
+        * than this number of samples ahead of the target sample
+        */
+       static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2;
+
+       /* If the total number of samples is unknown, use a large value, and
+        * force binary search immediately.
+        */
+       if(right_sample == 0) {
+               right_sample = (FLAC__uint64)(-1);
+               BINARY_SEARCH_AFTER_ITERATION = 0;
+       }
+
+       decoder->private_->target_sample = target_sample;
+       for( ; ; iteration++) {
+               if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) {
+                       if (iteration >= BINARY_SEARCH_AFTER_ITERATION) {
+                               pos = (right_pos + left_pos) / 2;
+                       }
+                       else {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+                               /* with MSVC you have to spoon feed it the casting */
+                               pos = (FLAC__uint64)((FLAC__double)(FLAC__int64)(target_sample - left_sample) / (FLAC__double)(FLAC__int64)(right_sample - left_sample) * (FLAC__double)(FLAC__int64)(right_pos - left_pos));
+#else
+                               pos = (FLAC__uint64)((FLAC__double)(target_sample - left_sample) / (FLAC__double)(right_sample - left_sample) * (FLAC__double)(right_pos - left_pos));
+#endif
+#else
+                               /* a little less accurate: */
+                               if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff))
+                                       pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample));
+                               else /* @@@ WATCHOUT, ~2TB limit */
+                                       pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16));
+#endif
+                               /* @@@ TODO: might want to limit pos to some distance
+                                * before EOF, to make sure we land before the last frame,
+                                * thereby getting a this_frame_sample and so having a better
+                                * estimate.
+                                */
+                       }
+
+                       /* physical seek */
+                       if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                               return false;
+                       }
+                       if(!FLAC__stream_decoder_flush(decoder)) {
+                               /* above call sets the state for us */
+                               return false;
+                       }
+                       did_a_seek = true;
+               }
+               else
+                       did_a_seek = false;
+
+               decoder->private_->got_a_frame = false;
+               if(!FLAC__stream_decoder_process_single(decoder)) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+               if(!decoder->private_->got_a_frame) {
+                       if(did_a_seek) {
+                               /* this can happen if we seek to a point after the last frame; we drop
+                                * to binary search right away in this case to avoid any wasted
+                                * iterations of proportional search.
+                                */
+                               right_pos = pos;
+                               BINARY_SEARCH_AFTER_ITERATION = 0;
+                       }
+                       else {
+                               /* this can probably only happen if total_samples is unknown and the
+                                * target_sample is past the end of the stream
+                                */
+                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                               return false;
+                       }
+               }
+               /* our write callback will change the state when it gets to the target frame */
+               else if(!decoder->private_->is_seeking) {
+                       break;
+               }
+               else {
+                       this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+                       FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+                       if (did_a_seek) {
+                               if (this_frame_sample <= target_sample) {
+                                       /* The 'equal' case should not happen, since
+                                        * FLAC__stream_decoder_process_single()
+                                        * should recognize that it has hit the
+                                        * target sample and we would exit through
+                                        * the 'break' above.
+                                        */
+                                       FLAC__ASSERT(this_frame_sample != target_sample);
+
+                                       left_sample = this_frame_sample;
+                                       /* sanity check to avoid infinite loop */
+                                       if (left_pos == pos) {
+                                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                                               return false;
+                                       }
+                                       left_pos = pos;
+                               }
+                               else if(this_frame_sample > target_sample) {
+                                       right_sample = this_frame_sample;
+                                       /* sanity check to avoid infinite loop */
+                                       if (right_pos == pos) {
+                                               decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                                               return false;
+                                       }
+                                       right_pos = pos;
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+#endif
+
+FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       (void)client_data;
+
+       if(*bytes > 0) {
+               *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file);
+               if(ferror(decoder->private_->file))
+                       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+               else if(*bytes == 0)
+                       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+               else
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+       }
+       else
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       (void)client_data;
+
+       if(decoder->private_->file == stdin)
+               return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+       else if(fseeko(decoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       off_t pos;
+       (void)client_data;
+
+       if(decoder->private_->file == stdin)
+               return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+       else if((pos = ftello(decoder->private_->file)) < 0)
+               return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+       else {
+               *absolute_byte_offset = (FLAC__uint64)pos;
+               return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+       }
+}
+
+FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+       struct stat filestats;
+       (void)client_data;
+
+       if(decoder->private_->file == stdin)
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+       else if(fstat(fileno(decoder->private_->file), &filestats) != 0)
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+       else {
+               *stream_length = (FLAC__uint64)filestats.st_size;
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+       }
+}
+
+FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+       (void)client_data;
+
+       return feof(decoder->private_->file)? true : false;
+}
diff --git a/src/libFLAC/stream_encoder.c b/src/libFLAC/stream_encoder.c
new file mode 100644 (file)
index 0000000..6d9859c
--- /dev/null
@@ -0,0 +1,4359 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for off_t */
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+#include "protected/stream_encoder.h"
+#include "private/bitwriter.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/cpu.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_helper.h"
+#include "private/ogg_mapping.h"
+#endif
+#include "private/stream_encoder_framing.h"
+#include "private/window.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* Exact Rice codeword length calculation is off by default.  The simple
+ * (and fast) estimation (of how many bits a residual value will be
+ * encoded with) in this encoder is very good, almost always yielding
+ * compression within 0.1% of exact calculation.
+ */
+#undef EXACT_RICE_BITS_CALCULATION
+/* Rice parameter searching is off by default.  The simple (and fast)
+ * parameter estimation in this encoder is very good, almost always
+ * yielding compression within 0.1% of the optimal parameters.
+ */
+#undef ENABLE_RICE_PARAMETER_SEARCH 
+
+
+typedef struct {
+       FLAC__int32 *data[FLAC__MAX_CHANNELS];
+       unsigned size; /* of each data[] in samples */
+       unsigned tail;
+} verify_input_fifo;
+
+typedef struct {
+       const FLAC__byte *data;
+       unsigned capacity;
+       unsigned bytes;
+} verify_output;
+
+typedef enum {
+       ENCODER_IN_MAGIC = 0,
+       ENCODER_IN_METADATA = 1,
+       ENCODER_IN_AUDIO = 2
+} EncoderStateHint;
+
+static struct CompressionLevels {
+       FLAC__bool do_mid_side_stereo;
+       FLAC__bool loose_mid_side_stereo;
+       unsigned max_lpc_order;
+       unsigned qlp_coeff_precision;
+       FLAC__bool do_qlp_coeff_prec_search;
+       FLAC__bool do_escape_coding;
+       FLAC__bool do_exhaustive_model_search;
+       unsigned min_residual_partition_order;
+       unsigned max_residual_partition_order;
+       unsigned rice_parameter_search_dist;
+} compression_levels_[] = {
+       { false, false,  0, 0, false, false, false, 0, 3, 0 },
+       { true , true ,  0, 0, false, false, false, 0, 3, 0 },
+       { true , false,  0, 0, false, false, false, 0, 3, 0 },
+       { false, false,  6, 0, false, false, false, 0, 4, 0 },
+       { true , true ,  8, 0, false, false, false, 0, 4, 0 },
+       { true , false,  8, 0, false, false, false, 0, 5, 0 },
+       { true , false,  8, 0, false, false, false, 0, 6, 0 },
+       { true , false,  8, 0, false, false, true , 0, 6, 0 },
+       { true , false, 12, 0, false, false, true , 0, 6, 0 }
+};
+
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamEncoder *encoder);
+static void free_(FLAC__StreamEncoder *encoder);
+static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block);
+static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block);
+static void update_metadata_(const FLAC__StreamEncoder *encoder);
+#if FLAC__HAS_OGG
+static void update_ogg_metadata_(FLAC__StreamEncoder *encoder);
+#endif
+static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block);
+static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block);
+
+static FLAC__bool process_subframe_(
+       FLAC__StreamEncoder *encoder,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       const FLAC__FrameHeader *frame_header,
+       unsigned subframe_bps,
+       const FLAC__int32 integer_signal[],
+       FLAC__Subframe *subframe[2],
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+       FLAC__int32 *residual[2],
+       unsigned *best_subframe,
+       unsigned *best_bits
+);
+
+static FLAC__bool add_subframe_(
+       FLAC__StreamEncoder *encoder,
+       unsigned blocksize,
+       unsigned subframe_bps,
+       const FLAC__Subframe *subframe,
+       FLAC__BitWriter *frame
+);
+
+static unsigned evaluate_constant_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal,
+       unsigned blocksize,
+       unsigned subframe_bps,
+       FLAC__Subframe *subframe
+);
+
+static unsigned evaluate_fixed_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal[],
+       FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       unsigned order,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__Subframe *subframe,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static unsigned evaluate_lpc_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal[],
+       FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       const FLAC__real lp_coeff[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       unsigned order,
+       unsigned qlp_coeff_precision,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__Subframe *subframe,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+#endif
+
+static unsigned evaluate_verbatim_subframe_(
+       FLAC__StreamEncoder *encoder, 
+       const FLAC__int32 signal[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       FLAC__Subframe *subframe
+);
+
+static unsigned find_best_partition_order_(
+       struct FLAC__StreamEncoderPrivate *private_,
+       const FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       unsigned bps,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__EntropyCodingMethod *best_ecm
+);
+
+static void precompute_partition_info_sums_(
+       const FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       unsigned bps
+);
+
+static void precompute_partition_info_escapes_(
+       const FLAC__int32 residual[],
+       unsigned raw_bits_per_partition[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned min_partition_order,
+       unsigned max_partition_order
+);
+
+static FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+       const FLAC__int32 residual[],
+#endif
+       const FLAC__uint64 abs_residual_partition_sums[],
+       const unsigned raw_bits_per_partition[],
+       const unsigned residual_samples,
+       const unsigned predictor_order,
+       const unsigned suggested_rice_parameter,
+       const unsigned rice_parameter_limit,
+       const unsigned rice_parameter_search_dist,
+       const unsigned partition_order,
+       const FLAC__bool search_for_escapes,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+       unsigned *bits
+);
+
+static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples);
+
+/* verify-related routines: */
+static void append_to_verify_fifo_(
+       verify_input_fifo *fifo,
+       const FLAC__int32 * const input[],
+       unsigned input_offset,
+       unsigned channels,
+       unsigned wide_samples
+);
+
+static void append_to_verify_fifo_interleaved_(
+       verify_input_fifo *fifo,
+       const FLAC__int32 input[],
+       unsigned input_offset,
+       unsigned channels,
+       unsigned wide_samples
+);
+
+static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, 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 FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+static FILE *get_binary_stdout_(void);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamEncoderPrivate {
+       unsigned input_capacity;                          /* current size (in samples) of the signal and residual buffers */
+       FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS];  /* the integer version of the input signal */
+       FLAC__int32 *integer_signal_mid_side[2];          /* the integer version of the mid-side input signal (stereo only) */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       FLAC__real *real_signal[FLAC__MAX_CHANNELS];      /* (@@@ currently unused) the floating-point version of the input signal */
+       FLAC__real *real_signal_mid_side[2];              /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */
+       FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */
+       FLAC__real *windowed_signal;                      /* the integer_signal[] * current window[] */
+#endif
+       unsigned subframe_bps[FLAC__MAX_CHANNELS];        /* the effective bits per sample of the input signal (stream bps - wasted bits) */
+       unsigned subframe_bps_mid_side[2];                /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */
+       FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */
+       FLAC__int32 *residual_workspace_mid_side[2][2];
+       FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
+       FLAC__Subframe subframe_workspace_mid_side[2][2];
+       FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
+       FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
+       FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
+       FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
+       unsigned best_subframe[FLAC__MAX_CHANNELS];       /* index (0 or 1) into 2nd dimension of the above workspaces */
+       unsigned best_subframe_mid_side[2];
+       unsigned best_subframe_bits[FLAC__MAX_CHANNELS];  /* size in bits of the best subframe for each channel */
+       unsigned best_subframe_bits_mid_side[2];
+       FLAC__uint64 *abs_residual_partition_sums;        /* workspace where the sum of abs(candidate residual) for each partition is stored */
+       unsigned *raw_bits_per_partition;                 /* workspace where the sum of silog2(candidate residual) for each partition is stored */
+       FLAC__BitWriter *frame;                           /* the current frame being worked on */
+       unsigned loose_mid_side_stereo_frames;            /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
+       unsigned loose_mid_side_stereo_frame_count;       /* number of frames using the current channel assignment */
+       FLAC__ChannelAssignment last_channel_assignment;
+       FLAC__StreamMetadata streaminfo;                  /* scratchpad for STREAMINFO as it is built */
+       FLAC__StreamMetadata_SeekTable *seek_table;       /* pointer into encoder->protected_->metadata_ where the seek table is */
+       unsigned current_sample_number;
+       unsigned current_frame_number;
+       FLAC__MD5Context md5context;
+       FLAC__CPUInfo cpuinfo;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+       unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+       void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+       void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+       void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#endif
+       FLAC__bool use_wide_by_block;          /* use slow 64-bit versions of some functions because of the block size */
+       FLAC__bool use_wide_by_partition;      /* use slow 64-bit versions of some functions because of the min partition order and blocksize */
+       FLAC__bool use_wide_by_order;          /* use slow 64-bit versions of some functions because of the lpc order */
+       FLAC__bool disable_constant_subframes;
+       FLAC__bool disable_fixed_subframes;
+       FLAC__bool disable_verbatim_subframes;
+#if FLAC__HAS_OGG
+       FLAC__bool is_ogg;
+#endif
+       FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */
+       FLAC__StreamEncoderSeekCallback seek_callback;
+       FLAC__StreamEncoderTellCallback tell_callback;
+       FLAC__StreamEncoderWriteCallback write_callback;
+       FLAC__StreamEncoderMetadataCallback metadata_callback;
+       FLAC__StreamEncoderProgressCallback progress_callback;
+       void *client_data;
+       unsigned first_seekpoint_to_check;
+       FILE *file;                            /* only used when encoding to a file */
+       FLAC__uint64 bytes_written;
+       FLAC__uint64 samples_written;
+       unsigned frames_written;
+       unsigned total_frames_estimate;
+       /* unaligned (original) pointers to allocated data */
+       FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS];
+       FLAC__int32 *integer_signal_mid_side_unaligned[2];
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */
+       FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */
+       FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS];
+       FLAC__real *windowed_signal_unaligned;
+#endif
+       FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2];
+       FLAC__int32 *residual_workspace_mid_side_unaligned[2][2];
+       FLAC__uint64 *abs_residual_partition_sums_unaligned;
+       unsigned *raw_bits_per_partition_unaligned;
+       /*
+        * These fields have been moved here from private function local
+        * declarations merely to save stack space during encoding.
+        */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */
+#endif
+       FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */
+       /*
+        * The data for the verify section
+        */
+       struct {
+               FLAC__StreamDecoder *decoder;
+               EncoderStateHint state_hint;
+               FLAC__bool needs_magic_hack;
+               verify_input_fifo input_fifo;
+               verify_output output;
+               struct {
+                       FLAC__uint64 absolute_sample;
+                       unsigned frame_number;
+                       unsigned channel;
+                       unsigned sample;
+                       FLAC__int32 expected;
+                       FLAC__int32 got;
+               } error_stats;
+       } verify;
+       FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
+} FLAC__StreamEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
+       "FLAC__STREAM_ENCODER_OK",
+       "FLAC__STREAM_ENCODER_UNINITIALIZED",
+       "FLAC__STREAM_ENCODER_OGG_ERROR",
+       "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
+       "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
+       "FLAC__STREAM_ENCODER_CLIENT_ERROR",
+       "FLAC__STREAM_ENCODER_IO_ERROR",
+       "FLAC__STREAM_ENCODER_FRAMING_ERROR",
+       "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = {
+       "FLAC__STREAM_ENCODER_INIT_STATUS_OK",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA",
+       "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__treamEncoderReadStatusString[] = {
+       "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE",
+       "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
+       "FLAC__STREAM_ENCODER_READ_STATUS_ABORT",
+       "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = {
+       "FLAC__STREAM_ENCODER_WRITE_STATUS_OK",
+       "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = {
+       "FLAC__STREAM_ENCODER_SEEK_STATUS_OK",
+       "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR",
+       "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = {
+       "FLAC__STREAM_ENCODER_TELL_STATUS_OK",
+       "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR",
+       "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED"
+};
+
+/* Number of samples that will be overread to watch for end of stream.  By
+ * 'overread', we mean that the FLAC__stream_encoder_process*() calls will
+ * always try to read blocksize+1 samples before encoding a block, so that
+ * even if the stream has a total sample count that is an integral multiple
+ * of the blocksize, we will still notice when we are encoding the last
+ * block.  This is needed, for example, to correctly set the end-of-stream
+ * marker in Ogg FLAC.
+ *
+ * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's
+ * not really any reason to change it.
+ */
+static const unsigned OVERREAD_ = 1;
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void)
+{
+       FLAC__StreamEncoder *encoder;
+       unsigned i;
+
+       FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+       encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder));
+       if(encoder == 0) {
+               return 0;
+       }
+
+       encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected));
+       if(encoder->protected_ == 0) {
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate));
+       if(encoder->private_ == 0) {
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_->frame = FLAC__bitwriter_new();
+       if(encoder->private_->frame == 0) {
+               free(encoder->private_);
+               free(encoder->protected_);
+               free(encoder);
+               return 0;
+       }
+
+       encoder->private_->file = 0;
+
+       set_defaults_(encoder);
+
+       encoder->private_->is_being_deleted = false;
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
+               encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
+       }
+       for(i = 0; i < 2; i++) {
+               encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
+               encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
+       }
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
+               encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
+       }
+       for(i = 0; i < 2; i++) {
+               encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
+               encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
+       }
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+       }
+       for(i = 0; i < 2; i++) {
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+       }
+       for(i = 0; i < 2; i++)
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+       encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+       return encoder;
+}
+
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->private_->frame);
+
+       encoder->private_->is_being_deleted = true;
+
+       (void)FLAC__stream_encoder_finish(encoder);
+
+       if(0 != encoder->private_->verify.decoder)
+               FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
+
+       for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+       }
+       for(i = 0; i < 2; i++) {
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+       }
+       for(i = 0; i < 2; i++)
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+       FLAC__bitwriter_delete(encoder->private_->frame);
+       free(encoder->private_);
+       free(encoder->protected_);
+       free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamEncoderInitStatus init_stream_internal_(
+       FLAC__StreamEncoder *encoder,
+       FLAC__StreamEncoderReadCallback read_callback,
+       FLAC__StreamEncoderWriteCallback write_callback,
+       FLAC__StreamEncoderSeekCallback seek_callback,
+       FLAC__StreamEncoderTellCallback tell_callback,
+       FLAC__StreamEncoderMetadataCallback metadata_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       unsigned i;
+       FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2;
+
+       FLAC__ASSERT(0 != encoder);
+
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+#if !FLAC__HAS_OGG
+       if(is_ogg)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
+
+       if(0 == write_callback || (seek_callback && 0 == tell_callback))
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS;
+
+       if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS;
+
+       if(encoder->protected_->channels != 2) {
+               encoder->protected_->do_mid_side_stereo = false;
+               encoder->protected_->loose_mid_side_stereo = false;
+       }
+       else if(!encoder->protected_->do_mid_side_stereo)
+               encoder->protected_->loose_mid_side_stereo = false;
+
+       if(encoder->protected_->bits_per_sample >= 32)
+               encoder->protected_->do_mid_side_stereo = false; /* since we currenty do 32-bit math, the side channel would have 33 bps and overflow */
+
+       if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;
+
+       if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate))
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE;
+
+       if(encoder->protected_->blocksize == 0) {
+               if(encoder->protected_->max_lpc_order == 0)
+                       encoder->protected_->blocksize = 1152;
+               else
+                       encoder->protected_->blocksize = 4096;
+       }
+
+       if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
+
+       if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER;
+
+       if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER;
+
+       if(encoder->protected_->qlp_coeff_precision == 0) {
+               if(encoder->protected_->bits_per_sample < 16) {
+                       /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */
+                       /* @@@ until then we'll make a guess */
+                       encoder->protected_->qlp_coeff_precision = max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2);
+               }
+               else if(encoder->protected_->bits_per_sample == 16) {
+                       if(encoder->protected_->blocksize <= 192)
+                               encoder->protected_->qlp_coeff_precision = 7;
+                       else if(encoder->protected_->blocksize <= 384)
+                               encoder->protected_->qlp_coeff_precision = 8;
+                       else if(encoder->protected_->blocksize <= 576)
+                               encoder->protected_->qlp_coeff_precision = 9;
+                       else if(encoder->protected_->blocksize <= 1152)
+                               encoder->protected_->qlp_coeff_precision = 10;
+                       else if(encoder->protected_->blocksize <= 2304)
+                               encoder->protected_->qlp_coeff_precision = 11;
+                       else if(encoder->protected_->blocksize <= 4608)
+                               encoder->protected_->qlp_coeff_precision = 12;
+                       else
+                               encoder->protected_->qlp_coeff_precision = 13;
+               }
+               else {
+                       if(encoder->protected_->blocksize <= 384)
+                               encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
+                       else if(encoder->protected_->blocksize <= 1152)
+                               encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
+                       else
+                               encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+               }
+               FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
+       }
+       else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION;
+
+       if(encoder->protected_->streamable_subset) {
+               if(
+                       encoder->protected_->blocksize != 192 &&
+                       encoder->protected_->blocksize != 576 &&
+                       encoder->protected_->blocksize != 1152 &&
+                       encoder->protected_->blocksize != 2304 &&
+                       encoder->protected_->blocksize != 4608 &&
+                       encoder->protected_->blocksize != 256 &&
+                       encoder->protected_->blocksize != 512 &&
+                       encoder->protected_->blocksize != 1024 &&
+                       encoder->protected_->blocksize != 2048 &&
+                       encoder->protected_->blocksize != 4096 &&
+                       encoder->protected_->blocksize != 8192 &&
+                       encoder->protected_->blocksize != 16384
+               )
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+               if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate))
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+               if(
+                       encoder->protected_->bits_per_sample != 8 &&
+                       encoder->protected_->bits_per_sample != 12 &&
+                       encoder->protected_->bits_per_sample != 16 &&
+                       encoder->protected_->bits_per_sample != 20 &&
+                       encoder->protected_->bits_per_sample != 24
+               )
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+               if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+               if(
+                       encoder->protected_->sample_rate <= 48000 &&
+                       (
+                               encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ ||
+                               encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ
+                       )
+               ) {
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+               }
+       }
+
+       if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+               encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
+       if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
+               encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
+
+#if FLAC__HAS_OGG
+       /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */
+       if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) {
+               unsigned i;
+               for(i = 1; i < encoder->protected_->num_metadata_blocks; i++) {
+                       if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+                               FLAC__StreamMetadata *vc = encoder->protected_->metadata[i];
+                               for( ; i > 0; i--)
+                                       encoder->protected_->metadata[i] = encoder->protected_->metadata[i-1];
+                               encoder->protected_->metadata[0] = vc;
+                               break;
+                       }
+               }
+       }
+#endif
+       /* keep track of any SEEKTABLE block */
+       if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) {
+               unsigned i;
+               for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+                       if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+                               encoder->private_->seek_table = &encoder->protected_->metadata[i]->data.seek_table;
+                               break; /* take only the first one */
+                       }
+               }
+       }
+
+       /* validate metadata */
+       if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+       metadata_has_seektable = false;
+       metadata_has_vorbis_comment = false;
+       metadata_picture_has_type1 = false;
+       metadata_picture_has_type2 = false;
+       for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+               const FLAC__StreamMetadata *m = encoder->protected_->metadata[i];
+               if(m->type == FLAC__METADATA_TYPE_STREAMINFO)
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+               else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+                       if(metadata_has_seektable) /* only one is allowed */
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                       metadata_has_seektable = true;
+                       if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+               }
+               else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+                       if(metadata_has_vorbis_comment) /* only one is allowed */
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                       metadata_has_vorbis_comment = true;
+               }
+               else if(m->type == FLAC__METADATA_TYPE_CUESHEET) {
+                       if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0))
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+               }
+               else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
+                       if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0))
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                       if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+                               if(metadata_picture_has_type1) /* there should only be 1 per stream */
+                                       return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                               metadata_picture_has_type1 = true;
+                               /* standard icon must be 32x32 pixel PNG */
+                               if(
+                                       m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && 
+                                       (
+                                               (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) ||
+                                               m->data.picture.width != 32 ||
+                                               m->data.picture.height != 32
+                                       )
+                               )
+                                       return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                       }
+                       else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+                               if(metadata_picture_has_type2) /* there should only be 1 per stream */
+                                       return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+                               metadata_picture_has_type2 = true;
+                       }
+               }
+       }
+
+       encoder->private_->input_capacity = 0;
+       for(i = 0; i < encoder->protected_->channels; i++) {
+               encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+               encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0;
+#endif
+       }
+       for(i = 0; i < 2; i++) {
+               encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+               encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0;
+#endif
+       }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       for(i = 0; i < encoder->protected_->num_apodizations; i++)
+               encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0;
+       encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0;
+#endif
+       for(i = 0; i < encoder->protected_->channels; i++) {
+               encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0;
+               encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0;
+               encoder->private_->best_subframe[i] = 0;
+       }
+       for(i = 0; i < 2; i++) {
+               encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
+               encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
+               encoder->private_->best_subframe_mid_side[i] = 0;
+       }
+       encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
+       encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       encoder->private_->loose_mid_side_stereo_frames = (unsigned)((FLAC__double)encoder->protected_->sample_rate * 0.4 / (FLAC__double)encoder->protected_->blocksize + 0.5);
+#else
+       /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */
+       /* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
+       FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350);
+       FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
+       FLAC__ASSERT(encoder->protected_->sample_rate <= 655350);
+       FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
+       encoder->private_->loose_mid_side_stereo_frames = (unsigned)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF);
+#endif
+       if(encoder->private_->loose_mid_side_stereo_frames == 0)
+               encoder->private_->loose_mid_side_stereo_frames = 1;
+       encoder->private_->loose_mid_side_stereo_frame_count = 0;
+       encoder->private_->current_sample_number = 0;
+       encoder->private_->current_frame_number = 0;
+
+       encoder->private_->use_wide_by_block = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(encoder->protected_->blocksize)+1 > 30);
+       encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */
+       encoder->private_->use_wide_by_partition = (false); /*@@@ need to set this */
+
+       /*
+        * get the CPU info and set the function pointers
+        */
+       FLAC__cpu_info(&encoder->private_->cpuinfo);
+       /* first default to the non-asm routines */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+#endif
+       encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients;
+       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide;
+       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients;
+#endif
+       /* now override with asm where appropriate */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+# ifndef FLAC__NO_ASM
+       if(encoder->private_->cpuinfo.use_asm) {
+#  ifdef FLAC__CPU_IA32
+               FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#   ifdef FLAC__HAS_NASM
+               if(encoder->private_->cpuinfo.data.ia32.sse) {
+                       if(encoder->protected_->max_lpc_order < 4)
+                               encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4;
+                       else if(encoder->protected_->max_lpc_order < 8)
+                               encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8;
+                       else if(encoder->protected_->max_lpc_order < 12)
+                               encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12;
+                       else
+                               encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+               }
+               else if(encoder->private_->cpuinfo.data.ia32._3dnow)
+                       encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow;
+               else
+                       encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+               if(encoder->private_->cpuinfo.data.ia32.mmx) {
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx;
+               }
+               else {
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+               }
+               if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov)
+                       encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
+#   endif /* FLAC__HAS_NASM */
+#  endif /* FLAC__CPU_IA32 */
+       }
+# endif /* !FLAC__NO_ASM */
+#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
+       /* finally override based on wide-ness if necessary */
+       if(encoder->private_->use_wide_by_block) {
+               encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide;
+       }
+
+       /* set state to OK; from here on, errors are fatal and we'll override the state then */
+       encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
+
+#if FLAC__HAS_OGG
+       encoder->private_->is_ogg = is_ogg;
+       if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+#endif
+
+       encoder->private_->read_callback = read_callback;
+       encoder->private_->write_callback = write_callback;
+       encoder->private_->seek_callback = seek_callback;
+       encoder->private_->tell_callback = tell_callback;
+       encoder->private_->metadata_callback = metadata_callback;
+       encoder->private_->client_data = client_data;
+
+       if(!resize_buffers_(encoder, encoder->protected_->blocksize)) {
+               /* the above function sets the state for us in case of an error */
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       if(!FLAC__bitwriter_init(encoder->private_->frame)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       /*
+        * Set up the verify stuff if necessary
+        */
+       if(encoder->protected_->verify) {
+               /*
+                * First, set up the fifo which will hold the
+                * original signal to compare against
+                */
+               encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
+               for(i = 0; i < encoder->protected_->channels; i++) {
+                       if(0 == (encoder->private_->verify.input_fifo.data[i] = (FLAC__int32*)safe_malloc_mul_2op_(sizeof(FLAC__int32), /*times*/encoder->private_->verify.input_fifo.size))) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+                               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+                       }
+               }
+               encoder->private_->verify.input_fifo.tail = 0;
+
+               /*
+                * Now set up a stream decoder for verification
+                */
+               encoder->private_->verify.decoder = FLAC__stream_decoder_new();
+               if(0 == encoder->private_->verify.decoder) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+
+               if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+       }
+       encoder->private_->verify.error_stats.absolute_sample = 0;
+       encoder->private_->verify.error_stats.frame_number = 0;
+       encoder->private_->verify.error_stats.channel = 0;
+       encoder->private_->verify.error_stats.sample = 0;
+       encoder->private_->verify.error_stats.expected = 0;
+       encoder->private_->verify.error_stats.got = 0;
+
+       /*
+        * These must be done before we write any metadata, because that
+        * calls the write_callback, which uses these values.
+        */
+       encoder->private_->first_seekpoint_to_check = 0;
+       encoder->private_->samples_written = 0;
+       encoder->protected_->streaminfo_offset = 0;
+       encoder->protected_->seektable_offset = 0;
+       encoder->protected_->audio_offset = 0;
+
+       /*
+        * write the stream header
+        */
+       if(encoder->protected_->verify)
+               encoder->private_->verify.state_hint = ENCODER_IN_MAGIC;
+       if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+       if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+               /* the above function sets the state for us in case of an error */
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       /*
+        * write the STREAMINFO metadata block
+        */
+       if(encoder->protected_->verify)
+               encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
+       encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+       encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */
+       encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+       encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */
+       encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize;
+       encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */
+       encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */
+       encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate;
+       encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels;
+       encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample;
+       encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */
+       memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
+       if(encoder->protected_->do_md5)
+               FLAC__MD5Init(&encoder->private_->md5context);
+       if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+       if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+               /* the above function sets the state for us in case of an error */
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       /*
+        * Now that the STREAMINFO block is written, we can init this to an
+        * absurdly-high value...
+        */
+       encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1;
+       /* ... and clear this to 0 */
+       encoder->private_->streaminfo.data.stream_info.total_samples = 0;
+
+       /*
+        * Check to see if the supplied metadata contains a VORBIS_COMMENT;
+        * if not, we will write an empty one (FLAC__add_metadata_block()
+        * automatically supplies the vendor string).
+        *
+        * WATCHOUT: the Ogg FLAC mapping requires us to write this block after
+        * the STREAMINFO.  (In the case that metadata_has_vorbis_comment is
+        * true it will have already insured that the metadata list is properly
+        * ordered.)
+        */
+       if(!metadata_has_vorbis_comment) {
+               FLAC__StreamMetadata vorbis_comment;
+               vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
+               vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
+               vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
+               vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
+               vorbis_comment.data.vorbis_comment.num_comments = 0;
+               vorbis_comment.data.vorbis_comment.comments = 0;
+               if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+               if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+                       /* the above function sets the state for us in case of an error */
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+       }
+
+       /*
+        * write the user's metadata blocks
+        */
+       for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+               encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
+               if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+               if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+                       /* the above function sets the state for us in case of an error */
+                       return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+               }
+       }
+
+       /* now that all the metadata is written, we save the stream offset */
+       if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       if(encoder->protected_->verify)
+               encoder->private_->verify.state_hint = ENCODER_IN_AUDIO;
+
+       return FLAC__STREAM_ENCODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(
+       FLAC__StreamEncoder *encoder,
+       FLAC__StreamEncoderWriteCallback write_callback,
+       FLAC__StreamEncoderSeekCallback seek_callback,
+       FLAC__StreamEncoderTellCallback tell_callback,
+       FLAC__StreamEncoderMetadataCallback metadata_callback,
+       void *client_data
+)
+{
+       return init_stream_internal_(
+               encoder,
+               /*read_callback=*/0,
+               write_callback,
+               seek_callback,
+               tell_callback,
+               metadata_callback,
+               client_data,
+               /*is_ogg=*/false
+       );
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(
+       FLAC__StreamEncoder *encoder,
+       FLAC__StreamEncoderReadCallback read_callback,
+       FLAC__StreamEncoderWriteCallback write_callback,
+       FLAC__StreamEncoderSeekCallback seek_callback,
+       FLAC__StreamEncoderTellCallback tell_callback,
+       FLAC__StreamEncoderMetadataCallback metadata_callback,
+       void *client_data
+)
+{
+       return init_stream_internal_(
+               encoder,
+               read_callback,
+               write_callback,
+               seek_callback,
+               tell_callback,
+               metadata_callback,
+               client_data,
+               /*is_ogg=*/true
+       );
+}
+static FLAC__StreamEncoderInitStatus init_FILE_internal_(
+       FLAC__StreamEncoder *encoder,
+       FILE *file,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       FLAC__StreamEncoderInitStatus init_status;
+
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != file);
+
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+       /* double protection */
+       if(file == 0) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       /*
+        * To make sure that our file does not go unclosed after an error, we
+        * must assign the FILE pointer before any further error can occur in
+        * this routine.
+        */
+       if(file == stdout)
+               file = get_binary_stdout_(); /* just to be safe */
+
+       encoder->private_->file = file;
+
+       encoder->private_->progress_callback = progress_callback;
+       encoder->private_->bytes_written = 0;
+       encoder->private_->samples_written = 0;
+       encoder->private_->frames_written = 0;
+
+       init_status = init_stream_internal_(
+               encoder,
+               encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0,
+               file_write_callback_,
+               encoder->private_->file == stdout? 0 : file_seek_callback_,
+               encoder->private_->file == stdout? 0 : file_tell_callback_,
+               /*metadata_callback=*/0,
+               client_data,
+               is_ogg
+       );
+       if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+               /* the above function sets the state for us in case of an error */
+               return init_status;
+       }
+
+       {
+               unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+
+               FLAC__ASSERT(blocksize != 0);
+               encoder->private_->total_frames_estimate = (unsigned)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
+       }
+
+       return init_status;
+}
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(
+       FLAC__StreamEncoder *encoder,
+       FILE *file,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data
+)
+{
+       return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false);
+}
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(
+       FLAC__StreamEncoder *encoder,
+       FILE *file,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data
+)
+{
+       return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamEncoderInitStatus init_file_internal_(
+       FLAC__StreamEncoder *encoder,
+       const char *filename,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data,
+       FLAC__bool is_ogg
+)
+{
+       FILE *file;
+
+       FLAC__ASSERT(0 != encoder);
+
+       /*
+        * To make sure that our file does not go unclosed after an error, we
+        * have to do the same entrance checks here that are later performed
+        * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned.
+        */
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+       file = filename? fopen(filename, "w+b") : stdout;
+
+       if(file == 0) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+               return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+       }
+
+       return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(
+       FLAC__StreamEncoder *encoder,
+       const char *filename,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data
+)
+{
+       return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(
+       FLAC__StreamEncoder *encoder,
+       const char *filename,
+       FLAC__StreamEncoderProgressCallback progress_callback,
+       void *client_data
+)
+{
+       return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
+{
+       FLAC__bool error = false;
+
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+
+       if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return true;
+
+       if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
+               if(encoder->private_->current_sample_number != 0) {
+                       const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number;
+                       encoder->protected_->blocksize = encoder->private_->current_sample_number;
+                       if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
+                               error = true;
+               }
+       }
+
+       if(encoder->protected_->do_md5)
+               FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context);
+
+       if(!encoder->private_->is_being_deleted) {
+               if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) {
+                       if(encoder->private_->seek_callback) {
+#if FLAC__HAS_OGG
+                               if(encoder->private_->is_ogg)
+                                       update_ogg_metadata_(encoder);
+                               else
+#endif
+                               update_metadata_(encoder);
+
+                               /* check if an error occurred while updating metadata */
+                               if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
+                                       error = true;
+                       }
+                       if(encoder->private_->metadata_callback)
+                               encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data);
+               }
+
+               if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) {
+                       if(!error)
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+                       error = true;
+               }
+       }
+
+       if(0 != encoder->private_->file) {
+               if(encoder->private_->file != stdout)
+                       fclose(encoder->private_->file);
+               encoder->private_->file = 0;
+       }
+
+#if FLAC__HAS_OGG
+       if(encoder->private_->is_ogg)
+               FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
+#endif
+
+       free_(encoder);
+       set_defaults_(encoder);
+
+       if(!error)
+               encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+       return !error;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+#if FLAC__HAS_OGG
+       /* can't check encoder->private_->is_ogg since that's not set until init time */
+       FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
+       return true;
+#else
+       (void)value;
+       return false;
+#endif
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+       encoder->protected_->verify = value;
+#endif
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->streamable_subset = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->do_md5 = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->channels = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->bits_per_sample = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->sample_rate = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__bool ok = true;
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0]))
+               value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1;
+       ok &= FLAC__stream_encoder_set_do_mid_side_stereo          (encoder, compression_levels_[value].do_mid_side_stereo);
+       ok &= FLAC__stream_encoder_set_loose_mid_side_stereo       (encoder, compression_levels_[value].loose_mid_side_stereo);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0
+       /* was: */
+       ok &= FLAC__stream_encoder_set_apodization                 (encoder, compression_levels_[value].apodization);
+       /* but it's too hard to specify the string in a locale-specific way */
+#else
+       encoder->protected_->num_apodizations = 1;
+       encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+       encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
+#endif
+       ok &= FLAC__stream_encoder_set_max_lpc_order               (encoder, compression_levels_[value].max_lpc_order);
+       ok &= FLAC__stream_encoder_set_qlp_coeff_precision         (encoder, compression_levels_[value].qlp_coeff_precision);
+       ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search    (encoder, compression_levels_[value].do_qlp_coeff_prec_search);
+       ok &= FLAC__stream_encoder_set_do_escape_coding            (encoder, compression_levels_[value].do_escape_coding);
+       ok &= FLAC__stream_encoder_set_do_exhaustive_model_search  (encoder, compression_levels_[value].do_exhaustive_model_search);
+       ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order);
+       ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order);
+       ok &= FLAC__stream_encoder_set_rice_parameter_search_dist  (encoder, compression_levels_[value].rice_parameter_search_dist);
+       return ok;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->blocksize = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->do_mid_side_stereo = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->loose_mid_side_stereo = value;
+       return true;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(0 != specification);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+       (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */
+#else
+       encoder->protected_->num_apodizations = 0;
+       while(1) {
+               const char *s = strchr(specification, ';');
+               const size_t n = s? (size_t)(s - specification) : strlen(specification);
+               if     (n==8  && 0 == strncmp("bartlett"     , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT;
+               else if(n==13 && 0 == strncmp("bartlett_hann", specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN;
+               else if(n==8  && 0 == strncmp("blackman"     , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN;
+               else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE;
+               else if(n==6  && 0 == strncmp("connes"       , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES;
+               else if(n==7  && 0 == strncmp("flattop"      , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP;
+               else if(n>7   && 0 == strncmp("gauss("       , specification, 6)) {
+                       FLAC__real stddev = (FLAC__real)strtod(specification+6, 0);
+                       if (stddev > 0.0 && stddev <= 0.5) {
+                               encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev;
+                               encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS;
+                       }
+               }
+               else if(n==7  && 0 == strncmp("hamming"      , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING;
+               else if(n==4  && 0 == strncmp("hann"         , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN;
+               else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL;
+               else if(n==7  && 0 == strncmp("nuttall"      , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL;
+               else if(n==9  && 0 == strncmp("rectangle"    , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE;
+               else if(n==8  && 0 == strncmp("triangle"     , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE;
+               else if(n>7   && 0 == strncmp("tukey("       , specification, 6)) {
+                       FLAC__real p = (FLAC__real)strtod(specification+6, 0);
+                       if (p >= 0.0 && p <= 1.0) {
+                               encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p;
+                               encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+                       }
+               }
+               else if(n==5  && 0 == strncmp("welch"        , specification, n))
+                       encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH;
+               if (encoder->protected_->num_apodizations == 32)
+                       break;
+               if (s)
+                       specification = s+1;
+               else
+                       break;
+       }
+       if(encoder->protected_->num_apodizations == 0) {
+               encoder->protected_->num_apodizations = 1;
+               encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+               encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+       }
+#endif
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->max_lpc_order = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->qlp_coeff_precision = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->do_qlp_coeff_prec_search = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+#if 0
+       /*@@@ deprecated: */
+       encoder->protected_->do_escape_coding = value;
+#else
+       (void)value;
+#endif
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->do_exhaustive_model_search = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->min_residual_partition_order = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->max_residual_partition_order = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+#if 0
+       /*@@@ deprecated: */
+       encoder->protected_->rice_parameter_search_dist = value;
+#else
+       (void)value;
+#endif
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->protected_->total_samples_estimate = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       if(0 == metadata)
+               num_blocks = 0;
+       if(0 == num_blocks)
+               metadata = 0;
+       /* realloc() does not do exactly what we want so... */
+       if(encoder->protected_->metadata) {
+               free(encoder->protected_->metadata);
+               encoder->protected_->metadata = 0;
+               encoder->protected_->num_metadata_blocks = 0;
+       }
+       if(num_blocks) {
+               FLAC__StreamMetadata **m;
+               if(0 == (m = (FLAC__StreamMetadata**)safe_malloc_mul_2op_(sizeof(m[0]), /*times*/num_blocks)))
+                       return false;
+               memcpy(m, metadata, sizeof(m[0]) * num_blocks);
+               encoder->protected_->metadata = m;
+               encoder->protected_->num_metadata_blocks = num_blocks;
+       }
+#if FLAC__HAS_OGG
+       if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks))
+               return false;
+#endif
+       return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->disable_constant_subframes = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->disable_fixed_subframes = value;
+       return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+               return false;
+       encoder->private_->disable_verbatim_subframes = value;
+       return true;
+}
+
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->state;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->verify)
+               return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder);
+       else
+               return FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR)
+               return FLAC__StreamEncoderStateString[encoder->protected_->state];
+       else
+               return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
+}
+
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       if(0 != absolute_sample)
+               *absolute_sample = encoder->private_->verify.error_stats.absolute_sample;
+       if(0 != frame_number)
+               *frame_number = encoder->private_->verify.error_stats.frame_number;
+       if(0 != channel)
+               *channel = encoder->private_->verify.error_stats.channel;
+       if(0 != sample)
+               *sample = encoder->private_->verify.error_stats.sample;
+       if(0 != expected)
+               *expected = encoder->private_->verify.error_stats.expected;
+       if(0 != got)
+               *got = encoder->private_->verify.error_stats.got;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->verify;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->streamable_subset;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->do_md5;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->channels;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->do_mid_side_stereo;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->loose_mid_side_stereo;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->max_lpc_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->qlp_coeff_precision;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->do_qlp_coeff_prec_search;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->do_escape_coding;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->do_exhaustive_model_search;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->min_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->max_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->rice_parameter_search_dist;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       return encoder->protected_->total_samples_estimate;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+       unsigned i, j = 0, channel;
+       const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+       do {
+               const unsigned n = min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j);
+
+               if(encoder->protected_->verify)
+                       append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
+
+               for(channel = 0; channel < channels; channel++)
+                       memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n);
+
+               if(encoder->protected_->do_mid_side_stereo) {
+                       FLAC__ASSERT(channels == 2);
+                       /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+                       for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+                               encoder->private_->integer_signal_mid_side[1][i] = buffer[0][j] - buffer[1][j];
+                               encoder->private_->integer_signal_mid_side[0][i] = (buffer[0][j] + buffer[1][j]) >> 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
+                       }
+               }
+               else
+                       j += n;
+
+               encoder->private_->current_sample_number += n;
+
+               /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+               if(encoder->private_->current_sample_number > blocksize) {
+                       FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_);
+                       FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+                       if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+                               return false;
+                       /* move unprocessed overread samples to beginnings of arrays */
+                       for(channel = 0; channel < channels; channel++)
+                               encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+                       if(encoder->protected_->do_mid_side_stereo) {
+                               encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+                               encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
+                       }
+                       encoder->private_->current_sample_number = 1;
+               }
+       } while(j < samples);
+
+       return true;
+}
+
+FLAC_API 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;
+       const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+       FLAC__ASSERT(0 != encoder);
+       FLAC__ASSERT(0 != encoder->private_);
+       FLAC__ASSERT(0 != encoder->protected_);
+       FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+       j = k = 0;
+       /*
+        * we have several flavors of the same basic loop, optimized for
+        * different conditions:
+        */
+       if(encoder->protected_->do_mid_side_stereo && channels == 2) {
+               /*
+                * stereo coding: unroll channel loop
+                */
+               do {
+                       if(encoder->protected_->verify)
+                               append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+                       /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+                       for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+                               encoder->private_->integer_signal[0][i] = mid = side = buffer[k++];
+                               x = buffer[k++];
+                               encoder->private_->integer_signal[1][i] = x;
+                               mid += x;
+                               side -= x;
+                               mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */
+                               encoder->private_->integer_signal_mid_side[1][i] = side;
+                               encoder->private_->integer_signal_mid_side[0][i] = mid;
+                       }
+                       encoder->private_->current_sample_number = i;
+                       /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+                       if(i > blocksize) {
+                               if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+                                       return false;
+                               /* move unprocessed overread samples to beginnings of arrays */
+                               FLAC__ASSERT(i == blocksize+OVERREAD_);
+                               FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+                               encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][blocksize];
+                               encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][blocksize];
+                               encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+                               encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
+                               encoder->private_->current_sample_number = 1;
+                       }
+               } while(j < samples);
+       }
+       else {
+               /*
+                * independent channel coding: buffer each channel in inner loop
+                */
+               do {
+                       if(encoder->protected_->verify)
+                               append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+                       /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+                       for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+                               for(channel = 0; channel < channels; channel++)
+                                       encoder->private_->integer_signal[channel][i] = buffer[k++];
+                       }
+                       encoder->private_->current_sample_number = i;
+                       /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+                       if(i > blocksize) {
+                               if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+                                       return false;
+                               /* move unprocessed overread samples to beginnings of arrays */
+                               FLAC__ASSERT(i == blocksize+OVERREAD_);
+                               FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+                               for(channel = 0; channel < channels; channel++)
+                                       encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+                               encoder->private_->current_sample_number = 1;
+                       }
+               } while(j < samples);
+       }
+
+       return true;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamEncoder *encoder)
+{
+       FLAC__ASSERT(0 != encoder);
+
+#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+       encoder->protected_->verify = true;
+#else
+       encoder->protected_->verify = false;
+#endif
+       encoder->protected_->streamable_subset = true;
+       encoder->protected_->do_md5 = true;
+       encoder->protected_->do_mid_side_stereo = false;
+       encoder->protected_->loose_mid_side_stereo = false;
+       encoder->protected_->channels = 2;
+       encoder->protected_->bits_per_sample = 16;
+       encoder->protected_->sample_rate = 44100;
+       encoder->protected_->blocksize = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       encoder->protected_->num_apodizations = 1;
+       encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+       encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
+       encoder->protected_->max_lpc_order = 0;
+       encoder->protected_->qlp_coeff_precision = 0;
+       encoder->protected_->do_qlp_coeff_prec_search = false;
+       encoder->protected_->do_exhaustive_model_search = false;
+       encoder->protected_->do_escape_coding = false;
+       encoder->protected_->min_residual_partition_order = 0;
+       encoder->protected_->max_residual_partition_order = 0;
+       encoder->protected_->rice_parameter_search_dist = 0;
+       encoder->protected_->total_samples_estimate = 0;
+       encoder->protected_->metadata = 0;
+       encoder->protected_->num_metadata_blocks = 0;
+
+       encoder->private_->seek_table = 0;
+       encoder->private_->disable_constant_subframes = false;
+       encoder->private_->disable_fixed_subframes = false;
+       encoder->private_->disable_verbatim_subframes = false;
+#if FLAC__HAS_OGG
+       encoder->private_->is_ogg = false;
+#endif
+       encoder->private_->read_callback = 0;
+       encoder->private_->write_callback = 0;
+       encoder->private_->seek_callback = 0;
+       encoder->private_->tell_callback = 0;
+       encoder->private_->metadata_callback = 0;
+       encoder->private_->progress_callback = 0;
+       encoder->private_->client_data = 0;
+
+#if FLAC__HAS_OGG
+       FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
+#endif
+}
+
+void free_(FLAC__StreamEncoder *encoder)
+{
+       unsigned i, channel;
+
+       FLAC__ASSERT(0 != encoder);
+       if(encoder->protected_->metadata) {
+               free(encoder->protected_->metadata);
+               encoder->protected_->metadata = 0;
+               encoder->protected_->num_metadata_blocks = 0;
+       }
+       for(i = 0; i < encoder->protected_->channels; i++) {
+               if(0 != encoder->private_->integer_signal_unaligned[i]) {
+                       free(encoder->private_->integer_signal_unaligned[i]);
+                       encoder->private_->integer_signal_unaligned[i] = 0;
+               }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+               if(0 != encoder->private_->real_signal_unaligned[i]) {
+                       free(encoder->private_->real_signal_unaligned[i]);
+                       encoder->private_->real_signal_unaligned[i] = 0;
+               }
+#endif
+       }
+       for(i = 0; i < 2; i++) {
+               if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) {
+                       free(encoder->private_->integer_signal_mid_side_unaligned[i]);
+                       encoder->private_->integer_signal_mid_side_unaligned[i] = 0;
+               }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+               if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) {
+                       free(encoder->private_->real_signal_mid_side_unaligned[i]);
+                       encoder->private_->real_signal_mid_side_unaligned[i] = 0;
+               }
+#endif
+       }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       for(i = 0; i < encoder->protected_->num_apodizations; i++) {
+               if(0 != encoder->private_->window_unaligned[i]) {
+                       free(encoder->private_->window_unaligned[i]);
+                       encoder->private_->window_unaligned[i] = 0;
+               }
+       }
+       if(0 != encoder->private_->windowed_signal_unaligned) {
+               free(encoder->private_->windowed_signal_unaligned);
+               encoder->private_->windowed_signal_unaligned = 0;
+       }
+#endif
+       for(channel = 0; channel < encoder->protected_->channels; channel++) {
+               for(i = 0; i < 2; i++) {
+                       if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) {
+                               free(encoder->private_->residual_workspace_unaligned[channel][i]);
+                               encoder->private_->residual_workspace_unaligned[channel][i] = 0;
+                       }
+               }
+       }
+       for(channel = 0; channel < 2; channel++) {
+               for(i = 0; i < 2; i++) {
+                       if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
+                               free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
+                               encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
+                       }
+               }
+       }
+       if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
+               free(encoder->private_->abs_residual_partition_sums_unaligned);
+               encoder->private_->abs_residual_partition_sums_unaligned = 0;
+       }
+       if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
+               free(encoder->private_->raw_bits_per_partition_unaligned);
+               encoder->private_->raw_bits_per_partition_unaligned = 0;
+       }
+       if(encoder->protected_->verify) {
+               for(i = 0; i < encoder->protected_->channels; i++) {
+                       if(0 != encoder->private_->verify.input_fifo.data[i]) {
+                               free(encoder->private_->verify.input_fifo.data[i]);
+                               encoder->private_->verify.input_fifo.data[i] = 0;
+                       }
+               }
+       }
+       FLAC__bitwriter_free(encoder->private_->frame);
+}
+
+FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
+{
+       FLAC__bool ok;
+       unsigned i, channel;
+
+       FLAC__ASSERT(new_blocksize > 0);
+       FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+       FLAC__ASSERT(encoder->private_->current_sample_number == 0);
+
+       /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
+       if(new_blocksize <= encoder->private_->input_capacity)
+               return true;
+
+       ok = true;
+
+       /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx()
+        * requires that the input arrays (in our case the integer signals)
+        * have a buffer of up to 3 zeroes in front (at negative indices) for
+        * alignment purposes; we use 4 in front to keep the data well-aligned.
+        */
+
+       for(i = 0; ok && i < encoder->protected_->channels; i++) {
+               ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]);
+               memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
+               encoder->private_->integer_signal[i] += 4;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+               if(encoder->protected_->max_lpc_order > 0)
+                       ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]);
+#endif
+#endif
+       }
+       for(i = 0; ok && i < 2; i++) {
+               ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]);
+               memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4);
+               encoder->private_->integer_signal_mid_side[i] += 4;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+               if(encoder->protected_->max_lpc_order > 0)
+                       ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]);
+#endif
+#endif
+       }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       if(ok && encoder->protected_->max_lpc_order > 0) {
+               for(i = 0; ok && i < encoder->protected_->num_apodizations; i++)
+                       ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]);
+               ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal);
+       }
+#endif
+       for(channel = 0; ok && channel < encoder->protected_->channels; channel++) {
+               for(i = 0; ok && i < 2; i++) {
+                       ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]);
+               }
+       }
+       for(channel = 0; ok && channel < 2; channel++) {
+               for(i = 0; ok && i < 2; i++) {
+                       ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
+               }
+       }
+       /* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */
+       /*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */
+       ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums);
+       if(encoder->protected_->do_escape_coding)
+               ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
+
+       /* now adjust the windows if the blocksize has changed */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) {
+               for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) {
+                       switch(encoder->protected_->apodizations[i].type) {
+                               case FLAC__APODIZATION_BARTLETT:
+                                       FLAC__window_bartlett(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_BARTLETT_HANN:
+                                       FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_BLACKMAN:
+                                       FLAC__window_blackman(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE:
+                                       FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_CONNES:
+                                       FLAC__window_connes(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_FLATTOP:
+                                       FLAC__window_flattop(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_GAUSS:
+                                       FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev);
+                                       break;
+                               case FLAC__APODIZATION_HAMMING:
+                                       FLAC__window_hamming(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_HANN:
+                                       FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_KAISER_BESSEL:
+                                       FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_NUTTALL:
+                                       FLAC__window_nuttall(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_RECTANGLE:
+                                       FLAC__window_rectangle(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_TRIANGLE:
+                                       FLAC__window_triangle(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               case FLAC__APODIZATION_TUKEY:
+                                       FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p);
+                                       break;
+                               case FLAC__APODIZATION_WELCH:
+                                       FLAC__window_welch(encoder->private_->window[i], new_blocksize);
+                                       break;
+                               default:
+                                       FLAC__ASSERT(0);
+                                       /* double protection */
+                                       FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+                                       break;
+                       }
+               }
+       }
+#endif
+
+       if(ok)
+               encoder->private_->input_capacity = new_blocksize;
+       else
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+
+       return ok;
+}
+
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block)
+{
+       const FLAC__byte *buffer;
+       size_t bytes;
+
+       FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+
+       if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       if(encoder->protected_->verify) {
+               encoder->private_->verify.output.data = buffer;
+               encoder->private_->verify.output.bytes = bytes;
+               if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
+                       encoder->private_->verify.needs_magic_hack = true;
+               }
+               else {
+                       if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) {
+                               FLAC__bitwriter_release_buffer(encoder->private_->frame);
+                               FLAC__bitwriter_clear(encoder->private_->frame);
+                               if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
+                                       encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+                               return false;
+                       }
+               }
+       }
+
+       if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+               FLAC__bitwriter_release_buffer(encoder->private_->frame);
+               FLAC__bitwriter_clear(encoder->private_->frame);
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return false;
+       }
+
+       FLAC__bitwriter_release_buffer(encoder->private_->frame);
+       FLAC__bitwriter_clear(encoder->private_->frame);
+
+       if(samples > 0) {
+               encoder->private_->streaminfo.data.stream_info.min_framesize = min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize);
+               encoder->private_->streaminfo.data.stream_info.max_framesize = max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize);
+       }
+
+       return true;
+}
+
+FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block)
+{
+       FLAC__StreamEncoderWriteStatus status;
+       FLAC__uint64 output_position = 0;
+
+       /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+       if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+       }
+
+       /*
+        * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
+        */
+       if(samples == 0) {
+               FLAC__MetadataType type = (buffer[0] & 0x7f);
+               if(type == FLAC__METADATA_TYPE_STREAMINFO)
+                       encoder->protected_->streaminfo_offset = output_position;
+               else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
+                       encoder->protected_->seektable_offset = output_position;
+       }
+
+       /*
+        * Mark the current seek point if hit (if audio_offset == 0 that
+        * means we're still writing metadata and haven't hit the first
+        * frame yet)
+        */
+       if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
+               const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+               const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
+               const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
+               FLAC__uint64 test_sample;
+               unsigned i;
+               for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
+                       test_sample = encoder->private_->seek_table->points[i].sample_number;
+                       if(test_sample > frame_last_sample) {
+                               break;
+                       }
+                       else if(test_sample >= frame_first_sample) {
+                               encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
+                               encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
+                               encoder->private_->seek_table->points[i].frame_samples = blocksize;
+                               encoder->private_->first_seekpoint_to_check++;
+                               /* DO NOT: "break;" and here's why:
+                                * The seektable template may contain more than one target
+                                * sample for any given frame; we will keep looping, generating
+                                * duplicate seekpoints for them, and we'll clean it up later,
+                                * just before writing the seektable back to the metadata.
+                                */
+                       }
+                       else {
+                               encoder->private_->first_seekpoint_to_check++;
+                       }
+               }
+       }
+
+#if FLAC__HAS_OGG
+       if(encoder->private_->is_ogg) {
+               status = FLAC__ogg_encoder_aspect_write_callback_wrapper(
+                       &encoder->protected_->ogg_encoder_aspect,
+                       buffer,
+                       bytes,
+                       samples,
+                       encoder->private_->current_frame_number,
+                       is_last_block,
+                       (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback,
+                       encoder,
+                       encoder->private_->client_data
+               );
+       }
+       else
+#endif
+       status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data);
+
+       if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+               encoder->private_->bytes_written += bytes;
+               encoder->private_->samples_written += samples;
+               /* we keep a high watermark on the number of frames written because
+                * when the encoder goes back to write metadata, 'current_frame'
+                * will drop back to 0.
+                */
+               encoder->private_->frames_written = max(encoder->private_->frames_written, encoder->private_->current_frame_number+1);
+       }
+       else
+               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+
+       return status;
+}
+
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks.  */
+void update_metadata_(const FLAC__StreamEncoder *encoder)
+{
+       FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+       const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+       const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+       const unsigned min_framesize = metadata->data.stream_info.min_framesize;
+       const unsigned max_framesize = metadata->data.stream_info.max_framesize;
+       const unsigned bps = metadata->data.stream_info.bits_per_sample;
+       FLAC__StreamEncoderSeekStatus seek_status;
+
+       FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+       /* All this is based on intimate knowledge of the stream header
+        * layout, but a change to the header format that would break this
+        * would also break all streams encoded in the previous format.
+        */
+
+       /*
+        * Write MD5 signature
+        */
+       {
+               const unsigned md5_offset =
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
+                       ) / 8;
+
+               if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+                       if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+               if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+       }
+
+       /*
+        * Write total samples
+        */
+       {
+               const unsigned total_samples_byte_offset =
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
+                               - 4
+                       ) / 8;
+
+               b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F);
+               b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
+               b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
+               b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
+               b[4] = (FLAC__byte)(samples & 0xFF);
+               if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+                       if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+               if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+       }
+
+       /*
+        * Write min/max framesize
+        */
+       {
+               const unsigned min_framesize_offset =
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+                       ) / 8;
+
+               b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
+               b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
+               b[2] = (FLAC__byte)(min_framesize & 0xFF);
+               b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
+               b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
+               b[5] = (FLAC__byte)(max_framesize & 0xFF);
+               if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+                       if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+               if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+       }
+
+       /*
+        * Write seektable
+        */
+       if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+               unsigned i;
+
+               FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+               FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+               if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+                       if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                       return;
+               }
+
+               for(i = 0; i < encoder->private_->seek_table->num_points; i++) {
+                       FLAC__uint64 xx;
+                       unsigned x;
+                       xx = encoder->private_->seek_table->points[i].sample_number;
+                       b[7] = (FLAC__byte)xx; xx >>= 8;
+                       b[6] = (FLAC__byte)xx; xx >>= 8;
+                       b[5] = (FLAC__byte)xx; xx >>= 8;
+                       b[4] = (FLAC__byte)xx; xx >>= 8;
+                       b[3] = (FLAC__byte)xx; xx >>= 8;
+                       b[2] = (FLAC__byte)xx; xx >>= 8;
+                       b[1] = (FLAC__byte)xx; xx >>= 8;
+                       b[0] = (FLAC__byte)xx; xx >>= 8;
+                       xx = encoder->private_->seek_table->points[i].stream_offset;
+                       b[15] = (FLAC__byte)xx; xx >>= 8;
+                       b[14] = (FLAC__byte)xx; xx >>= 8;
+                       b[13] = (FLAC__byte)xx; xx >>= 8;
+                       b[12] = (FLAC__byte)xx; xx >>= 8;
+                       b[11] = (FLAC__byte)xx; xx >>= 8;
+                       b[10] = (FLAC__byte)xx; xx >>= 8;
+                       b[9] = (FLAC__byte)xx; xx >>= 8;
+                       b[8] = (FLAC__byte)xx; xx >>= 8;
+                       x = encoder->private_->seek_table->points[i].frame_samples;
+                       b[17] = (FLAC__byte)x; x >>= 8;
+                       b[16] = (FLAC__byte)x; x >>= 8;
+                       if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+                               return;
+                       }
+               }
+       }
+}
+
+#if FLAC__HAS_OGG
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks.  */
+void update_ogg_metadata_(FLAC__StreamEncoder *encoder)
+{
+       /* the # of bytes in the 1st packet that precede the STREAMINFO */
+       static const unsigned FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH =
+               FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+               FLAC__OGG_MAPPING_MAGIC_LENGTH +
+               FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+               FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+               FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+               FLAC__STREAM_SYNC_LENGTH
+       ;
+       FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+       const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+       const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+       const unsigned min_framesize = metadata->data.stream_info.min_framesize;
+       const unsigned max_framesize = metadata->data.stream_info.max_framesize;
+       ogg_page page;
+
+       FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+       FLAC__ASSERT(0 != encoder->private_->seek_callback);
+
+       /* Pre-check that client supports seeking, since we don't want the
+        * ogg_helper code to ever have to deal with this condition.
+        */
+       if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED)
+               return;
+
+       /* All this is based on intimate knowledge of the stream header
+        * layout, but a change to the header format that would break this
+        * would also break all streams encoded in the previous format.
+        */
+
+       /**
+        ** Write STREAMINFO stats
+        **/
+       simple_ogg_page__init(&page);
+       if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+               simple_ogg_page__clear(&page);
+               return; /* state already set */
+       }
+
+       /*
+        * Write MD5 signature
+        */
+       {
+               const unsigned md5_offset =
+                       FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
+                       ) / 8;
+
+               if(md5_offset + 16 > (unsigned)page.body_len) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                       simple_ogg_page__clear(&page);
+                       return;
+               }
+               memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
+       }
+
+       /*
+        * Write total samples
+        */
+       {
+               const unsigned total_samples_byte_offset =
+                       FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
+                               - 4
+                       ) / 8;
+
+               if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                       simple_ogg_page__clear(&page);
+                       return;
+               }
+               b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
+               b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
+               b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
+               b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
+               b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
+               b[4] = (FLAC__byte)(samples & 0xFF);
+               memcpy(page.body + total_samples_byte_offset, b, 5);
+       }
+
+       /*
+        * Write min/max framesize
+        */
+       {
+               const unsigned min_framesize_offset =
+                       FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+                       FLAC__STREAM_METADATA_HEADER_LENGTH +
+                       (
+                               FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+                               FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+                       ) / 8;
+
+               if(min_framesize_offset + 6 > (unsigned)page.body_len) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                       simple_ogg_page__clear(&page);
+                       return;
+               }
+               b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
+               b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
+               b[2] = (FLAC__byte)(min_framesize & 0xFF);
+               b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
+               b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
+               b[5] = (FLAC__byte)(max_framesize & 0xFF);
+               memcpy(page.body + min_framesize_offset, b, 6);
+       }
+       if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+               simple_ogg_page__clear(&page);
+               return; /* state already set */
+       }
+       simple_ogg_page__clear(&page);
+
+       /*
+        * Write seektable
+        */
+       if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+               unsigned i;
+               FLAC__byte *p;
+
+               FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+               FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+               simple_ogg_page__init(&page);
+               if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+                       simple_ogg_page__clear(&page);
+                       return; /* state already set */
+               }
+
+               if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (unsigned)page.body_len) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+                       simple_ogg_page__clear(&page);
+                       return;
+               }
+
+               for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
+                       FLAC__uint64 xx;
+                       unsigned x;
+                       xx = encoder->private_->seek_table->points[i].sample_number;
+                       b[7] = (FLAC__byte)xx; xx >>= 8;
+                       b[6] = (FLAC__byte)xx; xx >>= 8;
+                       b[5] = (FLAC__byte)xx; xx >>= 8;
+                       b[4] = (FLAC__byte)xx; xx >>= 8;
+                       b[3] = (FLAC__byte)xx; xx >>= 8;
+                       b[2] = (FLAC__byte)xx; xx >>= 8;
+                       b[1] = (FLAC__byte)xx; xx >>= 8;
+                       b[0] = (FLAC__byte)xx; xx >>= 8;
+                       xx = encoder->private_->seek_table->points[i].stream_offset;
+                       b[15] = (FLAC__byte)xx; xx >>= 8;
+                       b[14] = (FLAC__byte)xx; xx >>= 8;
+                       b[13] = (FLAC__byte)xx; xx >>= 8;
+                       b[12] = (FLAC__byte)xx; xx >>= 8;
+                       b[11] = (FLAC__byte)xx; xx >>= 8;
+                       b[10] = (FLAC__byte)xx; xx >>= 8;
+                       b[9] = (FLAC__byte)xx; xx >>= 8;
+                       b[8] = (FLAC__byte)xx; xx >>= 8;
+                       x = encoder->private_->seek_table->points[i].frame_samples;
+                       b[17] = (FLAC__byte)x; x >>= 8;
+                       b[16] = (FLAC__byte)x; x >>= 8;
+                       memcpy(p, b, 18);
+               }
+
+               if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+                       simple_ogg_page__clear(&page);
+                       return; /* state already set */
+               }
+               simple_ogg_page__clear(&page);
+       }
+}
+#endif
+
+FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block)
+{
+       FLAC__uint16 crc;
+       FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+       /*
+        * Accumulate raw signal to the MD5 signature
+        */
+       if(encoder->protected_->do_md5 && !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;
+       }
+
+       /*
+        * Process the frame header and subframes into the frame bitbuffer
+        */
+       if(!process_subframes_(encoder, is_fractional_block)) {
+               /* the above function sets the state for us in case of an error */
+               return false;
+       }
+
+       /*
+        * Zero-pad the frame to a byte_boundary
+        */
+       if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       /*
+        * CRC-16 the whole thing
+        */
+       FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+       if(
+               !FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) ||
+               !FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN)
+       ) {
+               encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+               return false;
+       }
+
+       /*
+        * Write it
+        */
+       if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) {
+               /* the above function sets the state for us in case of an error */
+               return false;
+       }
+
+       /*
+        * Get ready for the next frame
+        */
+       encoder->private_->current_sample_number = 0;
+       encoder->private_->current_frame_number++;
+       encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
+
+       return true;
+}
+
+FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block)
+{
+       FLAC__FrameHeader frame_header;
+       unsigned channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
+       FLAC__bool do_independent, do_mid_side;
+
+       /*
+        * Calculate the min,max Rice partition orders
+        */
+       if(is_fractional_block) {
+               max_partition_order = 0;
+       }
+       else {
+               max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize);
+               max_partition_order = min(max_partition_order, encoder->protected_->max_residual_partition_order);
+       }
+       min_partition_order = min(min_partition_order, max_partition_order);
+
+       /*
+        * Setup the frame
+        */
+       frame_header.blocksize = encoder->protected_->blocksize;
+       frame_header.sample_rate = encoder->protected_->sample_rate;
+       frame_header.channels = encoder->protected_->channels;
+       frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
+       frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
+       frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+       frame_header.number.frame_number = encoder->private_->current_frame_number;
+
+       /*
+        * Figure out what channel assignments to try
+        */
+       if(encoder->protected_->do_mid_side_stereo) {
+               if(encoder->protected_->loose_mid_side_stereo) {
+                       if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
+                               do_independent = true;
+                               do_mid_side = true;
+                       }
+                       else {
+                               do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
+                               do_mid_side = !do_independent;
+                       }
+               }
+               else {
+                       do_independent = true;
+                       do_mid_side = true;
+               }
+       }
+       else {
+               do_independent = true;
+               do_mid_side = false;
+       }
+
+       FLAC__ASSERT(do_independent || do_mid_side);
+
+       /*
+        * Check for wasted bits; set effective bps for each subframe
+        */
+       if(do_independent) {
+               for(channel = 0; channel < encoder->protected_->channels; channel++) {
+                       const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
+                       encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
+                       encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
+               }
+       }
+       if(do_mid_side) {
+               FLAC__ASSERT(encoder->protected_->channels == 2);
+               for(channel = 0; channel < 2; channel++) {
+                       const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+                       encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
+                       encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
+               }
+       }
+
+       /*
+        * First do a normal encoding pass of each independent channel
+        */
+       if(do_independent) {
+               for(channel = 0; channel < encoder->protected_->channels; channel++) {
+                       if(!
+                               process_subframe_(
+                                       encoder,
+                                       min_partition_order,
+                                       max_partition_order,
+                                       &frame_header,
+                                       encoder->private_->subframe_bps[channel],
+                                       encoder->private_->integer_signal[channel],
+                                       encoder->private_->subframe_workspace_ptr[channel],
+                                       encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
+                                       encoder->private_->residual_workspace[channel],
+                                       encoder->private_->best_subframe+channel,
+                                       encoder->private_->best_subframe_bits+channel
+                               )
+                       )
+                               return false;
+               }
+       }
+
+       /*
+        * Now do mid and side channels if requested
+        */
+       if(do_mid_side) {
+               FLAC__ASSERT(encoder->protected_->channels == 2);
+
+               for(channel = 0; channel < 2; channel++) {
+                       if(!
+                               process_subframe_(
+                                       encoder,
+                                       min_partition_order,
+                                       max_partition_order,
+                                       &frame_header,
+                                       encoder->private_->subframe_bps_mid_side[channel],
+                                       encoder->private_->integer_signal_mid_side[channel],
+                                       encoder->private_->subframe_workspace_ptr_mid_side[channel],
+                                       encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
+                                       encoder->private_->residual_workspace_mid_side[channel],
+                                       encoder->private_->best_subframe_mid_side+channel,
+                                       encoder->private_->best_subframe_bits_mid_side+channel
+                               )
+                       )
+                               return false;
+               }
+       }
+
+       /*
+        * Compose the frame bitbuffer
+        */
+       if(do_mid_side) {
+               unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
+               FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
+               FLAC__ChannelAssignment channel_assignment;
+
+               FLAC__ASSERT(encoder->protected_->channels == 2);
+
+               if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
+                       channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
+               }
+               else {
+                       unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
+                       unsigned min_bits;
+                       int ca;
+
+                       FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0);
+                       FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE   == 1);
+                       FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE  == 2);
+                       FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE    == 3);
+                       FLAC__ASSERT(do_independent && do_mid_side);
+
+                       /* We have to figure out which channel assignent results in the smallest frame */
+                       bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits         [1];
+                       bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE  ] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits_mid_side[1];
+                       bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits         [1] + encoder->private_->best_subframe_bits_mid_side[1];
+                       bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE   ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
+
+                       channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+                       min_bits = bits[channel_assignment];
+                       for(ca = 1; ca <= 3; ca++) {
+                               if(bits[ca] < min_bits) {
+                                       min_bits = bits[ca];
+                                       channel_assignment = (FLAC__ChannelAssignment)ca;
+                               }
+                       }
+               }
+
+               frame_header.channel_assignment = channel_assignment;
+
+               if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                       return false;
+               }
+
+               switch(channel_assignment) {
+                       case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                               left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+                               right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                               left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+                               right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                               left_subframe  = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+                               right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                               left_subframe  = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
+                               right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+                               break;
+                       default:
+                               FLAC__ASSERT(0);
+               }
+
+               switch(channel_assignment) {
+                       case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                               left_bps  = encoder->private_->subframe_bps         [0];
+                               right_bps = encoder->private_->subframe_bps         [1];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                               left_bps  = encoder->private_->subframe_bps         [0];
+                               right_bps = encoder->private_->subframe_bps_mid_side[1];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                               left_bps  = encoder->private_->subframe_bps_mid_side[1];
+                               right_bps = encoder->private_->subframe_bps         [1];
+                               break;
+                       case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                               left_bps  = encoder->private_->subframe_bps_mid_side[0];
+                               right_bps = encoder->private_->subframe_bps_mid_side[1];
+                               break;
+                       default:
+                               FLAC__ASSERT(0);
+               }
+
+               /* note that encoder_add_subframe_ sets the state for us in case of an error */
+               if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
+                       return false;
+               if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame))
+                       return false;
+       }
+       else {
+               if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                       return false;
+               }
+
+               for(channel = 0; channel < encoder->protected_->channels; channel++) {
+                       if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) {
+                               /* the above function sets the state for us in case of an error */
+                               return false;
+                       }
+               }
+       }
+
+       if(encoder->protected_->loose_mid_side_stereo) {
+               encoder->private_->loose_mid_side_stereo_frame_count++;
+               if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
+                       encoder->private_->loose_mid_side_stereo_frame_count = 0;
+       }
+
+       encoder->private_->last_channel_assignment = frame_header.channel_assignment;
+
+       return true;
+}
+
+FLAC__bool process_subframe_(
+       FLAC__StreamEncoder *encoder,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       const FLAC__FrameHeader *frame_header,
+       unsigned subframe_bps,
+       const FLAC__int32 integer_signal[],
+       FLAC__Subframe *subframe[2],
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+       FLAC__int32 *residual[2],
+       unsigned *best_subframe,
+       unsigned *best_bits
+)
+{
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       FLAC__float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#else
+       FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+       FLAC__double lpc_residual_bits_per_sample;
+       FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */
+       FLAC__double lpc_error[FLAC__MAX_LPC_ORDER];
+       unsigned min_lpc_order, max_lpc_order, lpc_order;
+       unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+#endif
+       unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+       unsigned rice_parameter;
+       unsigned _candidate_bits, _best_bits;
+       unsigned _best_subframe;
+       /* only use RICE2 partitions if stream bps > 16 */
+       const unsigned rice_parameter_limit = FLAC__stream_encoder_get_bits_per_sample(encoder) > 16? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+       FLAC__ASSERT(frame_header->blocksize > 0);
+
+       /* verbatim subframe is the baseline against which we measure other compressed subframes */
+       _best_subframe = 0;
+       if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER)
+               _best_bits = UINT_MAX;
+       else
+               _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+
+       if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
+               unsigned signal_is_constant = false;
+               guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+               /* check for constant subframe */
+               if(
+                       !encoder->private_->disable_constant_subframes &&
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+                       fixed_residual_bits_per_sample[1] == 0.0
+#else
+                       fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO
+#endif
+               ) {
+                       /* the above means it's possible all samples are the same value; now double-check it: */
+                       unsigned i;
+                       signal_is_constant = true;
+                       for(i = 1; i < frame_header->blocksize; i++) {
+                               if(integer_signal[0] != integer_signal[i]) {
+                                       signal_is_constant = false;
+                                       break;
+                               }
+                       }
+               }
+               if(signal_is_constant) {
+                       _candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]);
+                       if(_candidate_bits < _best_bits) {
+                               _best_subframe = !_best_subframe;
+                               _best_bits = _candidate_bits;
+                       }
+               }
+               else {
+                       if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
+                               /* encode fixed */
+                               if(encoder->protected_->do_exhaustive_model_search) {
+                                       min_fixed_order = 0;
+                                       max_fixed_order = FLAC__MAX_FIXED_ORDER;
+                               }
+                               else {
+                                       min_fixed_order = max_fixed_order = guess_fixed_order;
+                               }
+                               if(max_fixed_order >= frame_header->blocksize)
+                                       max_fixed_order = frame_header->blocksize - 1;
+                               for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+                                       if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__float)subframe_bps)
+                                               continue; /* don't even try */
+                                       rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */
+#else
+                                       if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps)
+                                               continue; /* don't even try */
+                                       rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (unsigned)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */
+#endif
+                                       rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+                                       if(rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+                                               fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+                                               rice_parameter = rice_parameter_limit - 1;
+                                       }
+                                       _candidate_bits =
+                                               evaluate_fixed_subframe_(
+                                                       encoder,
+                                                       integer_signal,
+                                                       residual[!_best_subframe],
+                                                       encoder->private_->abs_residual_partition_sums,
+                                                       encoder->private_->raw_bits_per_partition,
+                                                       frame_header->blocksize,
+                                                       subframe_bps,
+                                                       fixed_order,
+                                                       rice_parameter,
+                                                       rice_parameter_limit,
+                                                       min_partition_order,
+                                                       max_partition_order,
+                                                       encoder->protected_->do_escape_coding,
+                                                       encoder->protected_->rice_parameter_search_dist,
+                                                       subframe[!_best_subframe],
+                                                       partitioned_rice_contents[!_best_subframe]
+                                               );
+                                       if(_candidate_bits < _best_bits) {
+                                               _best_subframe = !_best_subframe;
+                                               _best_bits = _candidate_bits;
+                                       }
+                               }
+                       }
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+                       /* encode lpc */
+                       if(encoder->protected_->max_lpc_order > 0) {
+                               if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
+                                       max_lpc_order = frame_header->blocksize-1;
+                               else
+                                       max_lpc_order = encoder->protected_->max_lpc_order;
+                               if(max_lpc_order > 0) {
+                                       unsigned a;
+                                       for (a = 0; a < encoder->protected_->num_apodizations; a++) {
+                                               FLAC__lpc_window_data(integer_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize);
+                                               encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc);
+                                               /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */
+                                               if(autoc[0] != 0.0) {
+                                                       FLAC__lpc_compute_lp_coefficients(autoc, &max_lpc_order, encoder->private_->lp_coeff, lpc_error);
+                                                       if(encoder->protected_->do_exhaustive_model_search) {
+                                                               min_lpc_order = 1;
+                                                       }
+                                                       else {
+                                                               const unsigned guess_lpc_order =
+                                                                       FLAC__lpc_compute_best_order(
+                                                                               lpc_error,
+                                                                               max_lpc_order,
+                                                                               frame_header->blocksize,
+                                                                               subframe_bps + (
+                                                                                       encoder->protected_->do_qlp_coeff_prec_search?
+                                                                                               FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */
+                                                                                               encoder->protected_->qlp_coeff_precision
+                                                                               )
+                                                                       );
+                                                               min_lpc_order = max_lpc_order = guess_lpc_order;
+                                                       }
+                                                       if(max_lpc_order >= frame_header->blocksize)
+                                                               max_lpc_order = frame_header->blocksize - 1;
+                                                       for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) {
+                                                               lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order);
+                                                               if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps)
+                                                                       continue; /* don't even try */
+                                                               rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */
+                                                               rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+                                                               if(rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+                                                                       fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+                                                                       rice_parameter = rice_parameter_limit - 1;
+                                                               }
+                                                               if(encoder->protected_->do_qlp_coeff_prec_search) {
+                                                                       min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+                                                                       /* try to ensure a 32-bit datapath throughout for 16bps(+1bps for side channel) or less */
+                                                                       if(subframe_bps <= 17) {
+                                                                               max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION);
+                                                                               max_qlp_coeff_precision = max(max_qlp_coeff_precision, min_qlp_coeff_precision);
+                                                                       }
+                                                                       else
+                                                                               max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+                                                               }
+                                                               else {
+                                                                       min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision;
+                                                               }
+                                                               for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) {
+                                                                       _candidate_bits =
+                                                                               evaluate_lpc_subframe_(
+                                                                                       encoder,
+                                                                                       integer_signal,
+                                                                                       residual[!_best_subframe],
+                                                                                       encoder->private_->abs_residual_partition_sums,
+                                                                                       encoder->private_->raw_bits_per_partition,
+                                                                                       encoder->private_->lp_coeff[lpc_order-1],
+                                                                                       frame_header->blocksize,
+                                                                                       subframe_bps,
+                                                                                       lpc_order,
+                                                                                       qlp_coeff_precision,
+                                                                                       rice_parameter,
+                                                                                       rice_parameter_limit,
+                                                                                       min_partition_order,
+                                                                                       max_partition_order,
+                                                                                       encoder->protected_->do_escape_coding,
+                                                                                       encoder->protected_->rice_parameter_search_dist,
+                                                                                       subframe[!_best_subframe],
+                                                                                       partitioned_rice_contents[!_best_subframe]
+                                                                               );
+                                                                       if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */
+                                                                               if(_candidate_bits < _best_bits) {
+                                                                                       _best_subframe = !_best_subframe;
+                                                                                       _best_bits = _candidate_bits;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+               }
+       }
+
+       /* under rare circumstances this can happen when all but lpc subframe types are disabled: */
+       if(_best_bits == UINT_MAX) {
+               FLAC__ASSERT(_best_subframe == 0);
+               _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+       }
+
+       *best_subframe = _best_subframe;
+       *best_bits = _best_bits;
+
+       return true;
+}
+
+FLAC__bool add_subframe_(
+       FLAC__StreamEncoder *encoder,
+       unsigned blocksize,
+       unsigned subframe_bps,
+       const FLAC__Subframe *subframe,
+       FLAC__BitWriter *frame
+)
+{
+       switch(subframe->type) {
+               case FLAC__SUBFRAME_TYPE_CONSTANT:
+                       if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                               return false;
+                       }
+                       break;
+               case FLAC__SUBFRAME_TYPE_FIXED:
+                       if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                               return false;
+                       }
+                       break;
+               case FLAC__SUBFRAME_TYPE_LPC:
+                       if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                               return false;
+                       }
+                       break;
+               case FLAC__SUBFRAME_TYPE_VERBATIM:
+                       if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
+                               encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+                               return false;
+                       }
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       return true;
+}
+
+#define SPOTCHECK_ESTIMATE 0
+#if SPOTCHECK_ESTIMATE
+static void spotcheck_subframe_estimate_(
+       FLAC__StreamEncoder *encoder,
+       unsigned blocksize,
+       unsigned subframe_bps,
+       const FLAC__Subframe *subframe,
+       unsigned estimate
+)
+{
+       FLAC__bool ret;
+       FLAC__BitWriter *frame = FLAC__bitwriter_new();
+       if(frame == 0) {
+               fprintf(stderr, "EST: can't allocate frame\n");
+               return;
+       }
+       if(!FLAC__bitwriter_init(frame)) {
+               fprintf(stderr, "EST: can't init frame\n");
+               return;
+       }
+       ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame);
+       FLAC__ASSERT(ret);
+       {
+               const unsigned actual = FLAC__bitwriter_get_input_bits_unconsumed(frame);
+               if(estimate != actual)
+                       fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate);
+       }
+       FLAC__bitwriter_delete(frame);
+}
+#endif
+
+unsigned evaluate_constant_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal,
+       unsigned blocksize,
+       unsigned subframe_bps,
+       FLAC__Subframe *subframe
+)
+{
+       unsigned estimate;
+       subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
+       subframe->data.constant.value = signal;
+
+       estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps;
+
+#if SPOTCHECK_ESTIMATE
+       spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+       (void)encoder, (void)blocksize;
+#endif
+
+       return estimate;
+}
+
+unsigned evaluate_fixed_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal[],
+       FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       unsigned order,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__Subframe *subframe,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+       unsigned i, residual_bits, estimate;
+       const unsigned residual_samples = blocksize - order;
+
+       FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
+
+       subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
+
+       subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+       subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+       subframe->data.fixed.residual = residual;
+
+       residual_bits =
+               find_best_partition_order_(
+                       encoder->private_,
+                       residual,
+                       abs_residual_partition_sums,
+                       raw_bits_per_partition,
+                       residual_samples,
+                       order,
+                       rice_parameter,
+                       rice_parameter_limit,
+                       min_partition_order,
+                       max_partition_order,
+                       subframe_bps,
+                       do_escape_coding,
+                       rice_parameter_search_dist,
+                       &subframe->data.fixed.entropy_coding_method
+               );
+
+       subframe->data.fixed.order = order;
+       for(i = 0; i < order; i++)
+               subframe->data.fixed.warmup[i] = signal[i];
+
+       estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+       spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+       return estimate;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned evaluate_lpc_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal[],
+       FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       const FLAC__real lp_coeff[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       unsigned order,
+       unsigned qlp_coeff_precision,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__Subframe *subframe,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+       FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+       unsigned i, residual_bits, estimate;
+       int quantization, ret;
+       const unsigned residual_samples = blocksize - order;
+
+       /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */
+       if(subframe_bps <= 16) {
+               FLAC__ASSERT(order > 0);
+               FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER);
+               qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order));
+       }
+
+       ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization);
+       if(ret != 0)
+               return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
+
+       if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+               if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+               else
+                       encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+       else
+               encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+
+       subframe->type = FLAC__SUBFRAME_TYPE_LPC;
+
+       subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+       subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+       subframe->data.lpc.residual = residual;
+
+       residual_bits =
+               find_best_partition_order_(
+                       encoder->private_,
+                       residual,
+                       abs_residual_partition_sums,
+                       raw_bits_per_partition,
+                       residual_samples,
+                       order,
+                       rice_parameter,
+                       rice_parameter_limit,
+                       min_partition_order,
+                       max_partition_order,
+                       subframe_bps,
+                       do_escape_coding,
+                       rice_parameter_search_dist,
+                       &subframe->data.lpc.entropy_coding_method
+               );
+
+       subframe->data.lpc.order = order;
+       subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
+       subframe->data.lpc.quantization_level = quantization;
+       memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER);
+       for(i = 0; i < order; i++)
+               subframe->data.lpc.warmup[i] = signal[i];
+
+       estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+       spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+       return estimate;
+}
+#endif
+
+unsigned evaluate_verbatim_subframe_(
+       FLAC__StreamEncoder *encoder,
+       const FLAC__int32 signal[],
+       unsigned blocksize,
+       unsigned subframe_bps,
+       FLAC__Subframe *subframe
+)
+{
+       unsigned estimate;
+
+       subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+       subframe->data.verbatim.data = signal;
+
+       estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps);
+
+#if SPOTCHECK_ESTIMATE
+       spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+       (void)encoder;
+#endif
+
+       return estimate;
+}
+
+unsigned find_best_partition_order_(
+       FLAC__StreamEncoderPrivate *private_,
+       const FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned raw_bits_per_partition[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned rice_parameter,
+       unsigned rice_parameter_limit,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       unsigned bps,
+       FLAC__bool do_escape_coding,
+       unsigned rice_parameter_search_dist,
+       FLAC__EntropyCodingMethod *best_ecm
+)
+{
+       unsigned residual_bits, best_residual_bits = 0;
+       unsigned best_parameters_index = 0;
+       unsigned best_partition_order = 0;
+       const unsigned blocksize = residual_samples + predictor_order;
+
+       max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order);
+       min_partition_order = min(min_partition_order, max_partition_order);
+
+       precompute_partition_info_sums_(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps);
+
+       if(do_escape_coding)
+               precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order);
+
+       {
+               int partition_order;
+               unsigned sum;
+
+               for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
+                       if(!
+                               set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+                                       residual,
+#endif
+                                       abs_residual_partition_sums+sum,
+                                       raw_bits_per_partition+sum,
+                                       residual_samples,
+                                       predictor_order,
+                                       rice_parameter,
+                                       rice_parameter_limit,
+                                       rice_parameter_search_dist,
+                                       (unsigned)partition_order,
+                                       do_escape_coding,
+                                       &private_->partitioned_rice_contents_extra[!best_parameters_index],
+                                       &residual_bits
+                               )
+                       )
+                       {
+                               FLAC__ASSERT(best_residual_bits != 0);
+                               break;
+                       }
+                       sum += 1u << partition_order;
+                       if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+                               best_residual_bits = residual_bits;
+                               best_parameters_index = !best_parameters_index;
+                               best_partition_order = partition_order;
+                       }
+               }
+       }
+
+       best_ecm->data.partitioned_rice.order = best_partition_order;
+
+       {
+               /*
+                * We are allowed to de-const the pointer based on our special
+                * knowledge; it is const to the outside world.
+                */
+               FLAC__EntropyCodingMethod_PartitionedRiceContents* prc = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_ecm->data.partitioned_rice.contents;
+               unsigned partition;
+
+               /* save best parameters and raw_bits */
+               FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(prc, max(6, best_partition_order));
+               memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partition_order)));
+               if(do_escape_coding)
+                       memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partition_order)));
+               /*
+                * Now need to check if the type should be changed to
+                * FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 based on the
+                * size of the rice parameters.
+                */
+               for(partition = 0; partition < (1u<<best_partition_order); partition++) {
+                       if(prc->parameters[partition] >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+                               best_ecm->type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2;
+                               break;
+                       }
+               }
+       }
+
+       return best_residual_bits;
+}
+
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+extern void precompute_partition_info_sums_32bit_asm_ia32_(
+       const FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned blocksize,
+       unsigned predictor_order,
+       unsigned min_partition_order,
+       unsigned max_partition_order
+);
+#endif
+
+void precompute_partition_info_sums_(
+       const FLAC__int32 residual[],
+       FLAC__uint64 abs_residual_partition_sums[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned min_partition_order,
+       unsigned max_partition_order,
+       unsigned bps
+)
+{
+       const unsigned default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+       unsigned partitions = 1u << max_partition_order;
+
+       FLAC__ASSERT(default_partition_samples > predictor_order);
+
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+       /* slightly pessimistic but still catches all common cases */
+       /* WATCHOUT: "+ bps" is an assumption that the average residual magnitude will not be more than "bps" bits */
+       if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) {
+               precompute_partition_info_sums_32bit_asm_ia32_(residual, abs_residual_partition_sums, residual_samples + predictor_order, predictor_order, min_partition_order, max_partition_order);
+               return;
+       }
+#endif
+
+       /* first do max_partition_order */
+       {
+               unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
+               /* slightly pessimistic but still catches all common cases */
+               /* WATCHOUT: "+ bps" is an assumption that the average residual magnitude will not be more than "bps" bits */
+               if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) {
+                       FLAC__uint32 abs_residual_partition_sum;
+
+                       for(partition = residual_sample = 0; partition < partitions; partition++) {
+                               end += default_partition_samples;
+                               abs_residual_partition_sum = 0;
+                               for( ; residual_sample < end; residual_sample++)
+                                       abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+                               abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+                       }
+               }
+               else { /* have to pessimistically use 64 bits for accumulator */
+                       FLAC__uint64 abs_residual_partition_sum;
+
+                       for(partition = residual_sample = 0; partition < partitions; partition++) {
+                               end += default_partition_samples;
+                               abs_residual_partition_sum = 0;
+                               for( ; residual_sample < end; residual_sample++)
+                                       abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+                               abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+                       }
+               }
+       }
+
+       /* now merge partitions for lower orders */
+       {
+               unsigned from_partition = 0, to_partition = partitions;
+               int partition_order;
+               for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) {
+                       unsigned i;
+                       partitions >>= 1;
+                       for(i = 0; i < partitions; i++) {
+                               abs_residual_partition_sums[to_partition++] =
+                                       abs_residual_partition_sums[from_partition  ] +
+                                       abs_residual_partition_sums[from_partition+1];
+                               from_partition += 2;
+                       }
+               }
+       }
+}
+
+void precompute_partition_info_escapes_(
+       const FLAC__int32 residual[],
+       unsigned raw_bits_per_partition[],
+       unsigned residual_samples,
+       unsigned predictor_order,
+       unsigned min_partition_order,
+       unsigned max_partition_order
+)
+{
+       int partition_order;
+       unsigned from_partition, to_partition = 0;
+       const unsigned blocksize = residual_samples + predictor_order;
+
+       /* first do max_partition_order */
+       for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
+               FLAC__int32 r;
+               FLAC__uint32 rmax;
+               unsigned partition, partition_sample, partition_samples, residual_sample;
+               const unsigned partitions = 1u << partition_order;
+               const unsigned default_partition_samples = blocksize >> partition_order;
+
+               FLAC__ASSERT(default_partition_samples > predictor_order);
+
+               for(partition = residual_sample = 0; partition < partitions; partition++) {
+                       partition_samples = default_partition_samples;
+                       if(partition == 0)
+                               partition_samples -= predictor_order;
+                       rmax = 0;
+                       for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
+                               r = residual[residual_sample++];
+                               /* OPT: maybe faster: rmax |= r ^ (r>>31) */
+                               if(r < 0)
+                                       rmax |= ~r;
+                               else
+                                       rmax |= r;
+                       }
+                       /* now we know all residual values are in the range [-rmax-1,rmax] */
+                       raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1;
+               }
+               to_partition = partitions;
+               break; /*@@@ yuck, should remove the 'for' loop instead */
+       }
+
+       /* now merge partitions for lower orders */
+       for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
+               unsigned m;
+               unsigned i;
+               const unsigned partitions = 1u << partition_order;
+               for(i = 0; i < partitions; i++) {
+                       m = raw_bits_per_partition[from_partition];
+                       from_partition++;
+                       raw_bits_per_partition[to_partition] = max(m, raw_bits_per_partition[from_partition]);
+                       from_partition++;
+                       to_partition++;
+               }
+       }
+}
+
+#ifdef EXACT_RICE_BITS_CALCULATION
+static FLaC__INLINE unsigned count_rice_bits_in_partition_(
+       const unsigned rice_parameter,
+       const unsigned partition_samples,
+       const FLAC__int32 *residual
+)
+{
+       unsigned i, partition_bits =
+               FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */
+               (1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */
+       ;
+       for(i = 0; i < partition_samples; i++)
+               partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter );
+       return partition_bits;
+}
+#else
+static FLaC__INLINE unsigned count_rice_bits_in_partition_(
+       const unsigned rice_parameter,
+       const unsigned partition_samples,
+       const FLAC__uint64 abs_residual_partition_sum
+)
+{
+       return
+               FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */
+               (1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */
+               (
+                       rice_parameter?
+                               (unsigned)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */
+                               : (unsigned)(abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */
+               )
+               - (partition_samples >> 1)
+               /* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum.
+                * The actual number of bits used is closer to the sum(for all i in the partition) of  abs(residual[i])>>(rice_parameter-1)
+                * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out.
+                * So the subtraction term tries to guess how many extra bits were contributed.
+                * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample.
+                */
+       ;
+}
+#endif
+
+FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+       const FLAC__int32 residual[],
+#endif
+       const FLAC__uint64 abs_residual_partition_sums[],
+       const unsigned raw_bits_per_partition[],
+       const unsigned residual_samples,
+       const unsigned predictor_order,
+       const unsigned suggested_rice_parameter,
+       const unsigned rice_parameter_limit,
+       const unsigned rice_parameter_search_dist,
+       const unsigned partition_order,
+       const FLAC__bool search_for_escapes,
+       FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+       unsigned *bits
+)
+{
+       unsigned rice_parameter, partition_bits;
+       unsigned best_partition_bits, best_rice_parameter = 0;
+       unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+       unsigned *parameters, *raw_bits;
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+       unsigned min_rice_parameter, max_rice_parameter;
+#else
+       (void)rice_parameter_search_dist;
+#endif
+
+       FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER);
+       FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER);
+
+       FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
+       parameters = partitioned_rice_contents->parameters;
+       raw_bits = partitioned_rice_contents->raw_bits;
+
+       if(partition_order == 0) {
+               best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+               if(rice_parameter_search_dist) {
+                       if(suggested_rice_parameter < rice_parameter_search_dist)
+                               min_rice_parameter = 0;
+                       else
+                               min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
+                       max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
+                       if(max_rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+                               fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1);
+#endif
+                               max_rice_parameter = rice_parameter_limit - 1;
+                       }
+               }
+               else
+                       min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
+
+               for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#else
+                       rice_parameter = suggested_rice_parameter;
+#endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+                       partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, residual);
+#else
+                       partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]);
+#endif
+                       if(partition_bits < best_partition_bits) {
+                               best_rice_parameter = rice_parameter;
+                               best_partition_bits = partition_bits;
+                       }
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+               }
+#endif
+               if(search_for_escapes) {
+                       partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples;
+                       if(partition_bits <= best_partition_bits) {
+                               raw_bits[0] = raw_bits_per_partition[0];
+                               best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */
+                               best_partition_bits = partition_bits;
+                       }
+                       else
+                               raw_bits[0] = 0;
+               }
+               parameters[0] = best_rice_parameter;
+               bits_ += best_partition_bits;
+       }
+       else {
+               unsigned partition, residual_sample;
+               unsigned partition_samples;
+               FLAC__uint64 mean, k;
+               const unsigned partitions = 1u << partition_order;
+               for(partition = residual_sample = 0; partition < partitions; partition++) {
+                       partition_samples = (residual_samples+predictor_order) >> partition_order;
+                       if(partition == 0) {
+                               if(partition_samples <= predictor_order)
+                                       return false;
+                               else
+                                       partition_samples -= predictor_order;
+                       }
+                       mean = abs_residual_partition_sums[partition];
+                       /* we are basically calculating the size in bits of the
+                        * average residual magnitude in the partition:
+                        *   rice_parameter = floor(log2(mean/partition_samples))
+                        * 'mean' is not a good name for the variable, it is
+                        * actually the sum of magnitudes of all residual values
+                        * in the partition, so the actual mean is
+                        * mean/partition_samples
+                        */
+                       for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
+                               ;
+                       if(rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+                               fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+                               rice_parameter = rice_parameter_limit - 1;
+                       }
+
+                       best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+                       if(rice_parameter_search_dist) {
+                               if(rice_parameter < rice_parameter_search_dist)
+                                       min_rice_parameter = 0;
+                               else
+                                       min_rice_parameter = rice_parameter - rice_parameter_search_dist;
+                               max_rice_parameter = rice_parameter + rice_parameter_search_dist;
+                               if(max_rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+                                       fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1);
+#endif
+                                       max_rice_parameter = rice_parameter_limit - 1;
+                               }
+                       }
+                       else
+                               min_rice_parameter = max_rice_parameter = rice_parameter;
+
+                       for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+                               partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample);
+#else
+                               partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]);
+#endif
+                               if(partition_bits < best_partition_bits) {
+                                       best_rice_parameter = rice_parameter;
+                                       best_partition_bits = partition_bits;
+                               }
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+                       }
+#endif
+                       if(search_for_escapes) {
+                               partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples;
+                               if(partition_bits <= best_partition_bits) {
+                                       raw_bits[partition] = raw_bits_per_partition[partition];
+                                       best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */
+                                       best_partition_bits = partition_bits;
+                               }
+                               else
+                                       raw_bits[partition] = 0;
+                       }
+                       parameters[partition] = best_rice_parameter;
+                       bits_ += best_partition_bits;
+                       residual_sample += partition_samples;
+               }
+       }
+
+       *bits = bits_;
+       return true;
+}
+
+unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples)
+{
+       unsigned i, shift;
+       FLAC__int32 x = 0;
+
+       for(i = 0; i < samples && !(x&1); i++)
+               x |= signal[i];
+
+       if(x == 0) {
+               shift = 0;
+       }
+       else {
+               for(shift = 0; !(x&1); shift++)
+                       x >>= 1;
+       }
+
+       if(shift > 0) {
+               for(i = 0; i < samples; i++)
+                        signal[i] >>= shift;
+       }
+
+       return shift;
+}
+
+void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+       unsigned channel;
+
+       for(channel = 0; channel < channels; channel++)
+               memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
+
+       fifo->tail += wide_samples;
+
+       FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+       unsigned channel;
+       unsigned sample, wide_sample;
+       unsigned tail = fifo->tail;
+
+       sample = input_offset * channels;
+       for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+               for(channel = 0; channel < channels; channel++)
+                       fifo->data[channel][tail] = input[sample++];
+               tail++;
+       }
+       fifo->tail = tail;
+
+       FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+       const size_t encoded_bytes = encoder->private_->verify.output.bytes;
+       (void)decoder;
+
+       if(encoder->private_->verify.needs_magic_hack) {
+               FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
+               *bytes = FLAC__STREAM_SYNC_LENGTH;
+               memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
+               encoder->private_->verify.needs_magic_hack = false;
+       }
+       else {
+               if(encoded_bytes == 0) {
+                       /*
+                        * If we get here, a FIFO underflow has occurred,
+                        * which means there is a bug somewhere.
+                        */
+                       FLAC__ASSERT(0);
+                       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+               }
+               else if(encoded_bytes < *bytes)
+                       *bytes = encoded_bytes;
+               memcpy(buffer, encoder->private_->verify.output.data, *bytes);
+               encoder->private_->verify.output.data += *bytes;
+               encoder->private_->verify.output.bytes -= *bytes;
+       }
+
+       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
+       unsigned channel;
+       const unsigned channels = frame->header.channels;
+       const unsigned blocksize = frame->header.blocksize;
+       const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize;
+
+       (void)decoder;
+
+       for(channel = 0; channel < channels; channel++) {
+               if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) {
+                       unsigned i, sample = 0;
+                       FLAC__int32 expect = 0, got = 0;
+
+                       for(i = 0; i < blocksize; i++) {
+                               if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
+                                       sample = i;
+                                       expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
+                                       got = (FLAC__int32)buffer[channel][i];
+                                       break;
+                               }
+                       }
+                       FLAC__ASSERT(i < blocksize);
+                       FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+                       encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
+                       encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize);
+                       encoder->private_->verify.error_stats.channel = channel;
+                       encoder->private_->verify.error_stats.sample = sample;
+                       encoder->private_->verify.error_stats.expected = expect;
+                       encoder->private_->verify.error_stats.got = got;
+                       encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               }
+       }
+       /* dequeue the frame from the fifo */
+       encoder->private_->verify.input_fifo.tail -= blocksize;
+       FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_);
+       for(channel = 0; channel < channels; channel++)
+               memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0]));
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       (void)decoder, (void)metadata, (void)client_data;
+}
+
+void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+       (void)decoder, (void)status;
+       encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+}
+
+FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       (void)client_data;
+
+       *bytes = fread(buffer, 1, *bytes, encoder->private_->file);
+       if (*bytes == 0) {
+               if (feof(encoder->private_->file))
+                       return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+               else if (ferror(encoder->private_->file))
+                       return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+       }
+       return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       (void)client_data;
+
+       if(fseeko(encoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       off_t offset;
+
+       (void)client_data;
+
+       offset = ftello(encoder->private_->file);
+
+       if(offset < 0) {
+               return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+       }
+       else {
+               *absolute_byte_offset = (FLAC__uint64)offset;
+               return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+       }
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       (void)client_data, (void)current_frame;
+
+       if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) {
+               FLAC__bool call_it = 0 != encoder->private_->progress_callback && (
+#if FLAC__HAS_OGG
+                       /* We would like to be able to use 'samples > 0' in the
+                        * clause here but currently because of the nature of our
+                        * Ogg writing implementation, 'samples' is always 0 (see
+                        * ogg_encoder_aspect.c).  The downside is extra progress
+                        * callbacks.
+                        */
+                       encoder->private_->is_ogg? true :
+#endif
+                       samples > 0
+               );
+               if(call_it) {
+                       /* NOTE: We have to add +bytes, +samples, and +1 to the stats
+                        * because at this point in the callback chain, the stats
+                        * have not been updated.  Only after we return and control
+                        * gets back to write_frame_() are the stats updated
+                        */
+                       encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data);
+               }
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+       }
+       else
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+}
+
+/*
+ * This will forcibly set stdout to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdout_(void)
+{
+       /* if something breaks here it is probably due to the presence or
+        * absence of an underscore before the identifiers 'setmode',
+        * 'fileno', and/or 'O_BINARY'; check your system header files.
+        */
+#if defined _MSC_VER || defined __MINGW32__
+       _setmode(_fileno(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+       /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+       setmode(_fileno(stdout), _O_BINARY);
+#elif defined __EMX__
+       setmode(fileno(stdout), O_BINARY);
+#endif
+
+       return stdout;
+}
diff --git a/src/libFLAC/stream_encoder_framing.c b/src/libFLAC/stream_encoder_framing.c
new file mode 100644 (file)
index 0000000..939955b
--- /dev/null
@@ -0,0 +1,553 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h> /* for strlen() */
+#include "private/stream_encoder_framing.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method);
+static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended);
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw)
+{
+       unsigned i, j;
+       const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
+               return false;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
+               return false;
+
+       /*
+        * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
+        */
+       i = metadata->length;
+       if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+               FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
+               i -= metadata->data.vorbis_comment.vendor_string.length;
+               i += vendor_string_length;
+       }
+       FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+       if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN))
+               return false;
+
+       switch(metadata->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN))
+                               return false;
+                       FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+                               return false;
+                       FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+                               return false;
+                       FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+                               return false;
+                       FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+                               return false;
+                       FLAC__ASSERT(metadata->data.stream_info.channels > 0);
+                       FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+                               return false;
+                       FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0);
+                       FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+                               return false;
+                       if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
+                               return false;
+                       break;
+               case FLAC__METADATA_TYPE_PADDING:
+                       if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8))
+                               return false;
+                       break;
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
+                               return false;
+                       if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)))
+                               return false;
+                       break;
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       for(i = 0; i < metadata->data.seek_table.num_points; i++) {
+                               if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+                                       return false;
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
+                               return false;
+                       if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments))
+                               return false;
+                       for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+                               if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length))
+                                       return false;
+                               if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length))
+                                       return false;
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+                       if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+                               return false;
+                       if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+                               return false;
+                       for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) {
+                               const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i;
+
+                               if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+                                       return false;
+                               FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+                               if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+                                       return false;
+                               for(j = 0; j < track->num_indices; j++) {
+                                       const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+
+                                       if(!FLAC__bitwriter_write_raw_uint64(bw, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+                                               return false;
+                                       if(!FLAC__bitwriter_write_raw_uint32(bw, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+                                               return false;
+                                       if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+                                               return false;
+                               }
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_PICTURE:
+                       {
+                               size_t len;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+                                       return false;
+                               len = strlen(metadata->data.picture.mime_type);
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len))
+                                       return false;
+                               len = strlen((const char *)metadata->data.picture.description);
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+                                       return false;
+                               if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length))
+                                       return false;
+                       }
+                       break;
+               default:
+                       if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
+                               return false;
+                       break;
+       }
+
+       FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+       return true;
+}
+
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
+{
+       unsigned u, blocksize_hint, sample_rate_hint;
+       FLAC__byte crc;
+
+       FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+               return false;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
+               return false;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN))
+               return false;
+
+       FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE);
+       /* when this assertion holds true, any legal blocksize can be expressed in the frame header */
+       FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u);
+       blocksize_hint = 0;
+       switch(header->blocksize) {
+               case   192: u = 1; break;
+               case   576: u = 2; break;
+               case  1152: u = 3; break;
+               case  2304: u = 4; break;
+               case  4608: u = 5; break;
+               case   256: u = 8; break;
+               case   512: u = 9; break;
+               case  1024: u = 10; break;
+               case  2048: u = 11; break;
+               case  4096: u = 12; break;
+               case  8192: u = 13; break;
+               case 16384: u = 14; break;
+               case 32768: u = 15; break;
+               default:
+                       if(header->blocksize <= 0x100)
+                               blocksize_hint = u = 6;
+                       else
+                               blocksize_hint = u = 7;
+                       break;
+       }
+       if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN))
+               return false;
+
+       FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate));
+       sample_rate_hint = 0;
+       switch(header->sample_rate) {
+               case  88200: u = 1; break;
+               case 176400: u = 2; break;
+               case 192000: u = 3; break;
+               case   8000: u = 4; break;
+               case  16000: u = 5; break;
+               case  22050: u = 6; break;
+               case  24000: u = 7; break;
+               case  32000: u = 8; break;
+               case  44100: u = 9; break;
+               case  48000: u = 10; break;
+               case  96000: u = 11; break;
+               default:
+                       if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0)
+                               sample_rate_hint = u = 12;
+                       else if(header->sample_rate % 10 == 0)
+                               sample_rate_hint = u = 14;
+                       else if(header->sample_rate <= 0xffff)
+                               sample_rate_hint = u = 13;
+                       else
+                               u = 0;
+                       break;
+       }
+       if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN))
+               return false;
+
+       FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS);
+       switch(header->channel_assignment) {
+               case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                       u = header->channels - 1;
+                       break;
+               case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                       FLAC__ASSERT(header->channels == 2);
+                       u = 8;
+                       break;
+               case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                       FLAC__ASSERT(header->channels == 2);
+                       u = 9;
+                       break;
+               case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                       FLAC__ASSERT(header->channels == 2);
+                       u = 10;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+       if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
+               return false;
+
+       FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
+       switch(header->bits_per_sample) {
+               case 8 : u = 1; break;
+               case 12: u = 2; break;
+               case 16: u = 4; break;
+               case 20: u = 5; break;
+               case 24: u = 6; break;
+               default: u = 0; break;
+       }
+       if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
+               return false;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
+               return false;
+
+       if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+               if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number))
+                       return false;
+       }
+       else {
+               if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number))
+                       return false;
+       }
+
+       if(blocksize_hint)
+               if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16))
+                       return false;
+
+       switch(sample_rate_hint) {
+               case 12:
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
+                               return false;
+                       break;
+               case 13:
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
+                               return false;
+                       break;
+               case 14:
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16))
+                               return false;
+                       break;
+       }
+
+       /* write the CRC */
+       if(!FLAC__bitwriter_get_write_crc8(bw, &crc))
+               return false;
+       if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN))
+               return false;
+
+       return true;
+}
+
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+       FLAC__bool ok;
+
+       ok =
+               FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) &&
+               (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) &&
+               FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps)
+       ;
+
+       return ok;
+}
+
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+       unsigned i;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+               return false;
+       if(wasted_bits)
+               if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+                       return false;
+
+       for(i = 0; i < subframe->order; i++)
+               if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+                       return false;
+
+       if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
+               return false;
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!add_residual_partitioned_rice_(
+                               bw,
+                               subframe->residual,
+                               residual_samples,
+                               subframe->order,
+                               subframe->entropy_coding_method.data.partitioned_rice.contents->parameters,
+                               subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits,
+                               subframe->entropy_coding_method.data.partitioned_rice.order,
+                               /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
+                       ))
+                               return false;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       return true;
+}
+
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+       unsigned i;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+               return false;
+       if(wasted_bits)
+               if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+                       return false;
+
+       for(i = 0; i < subframe->order; i++)
+               if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+                       return false;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+               return false;
+       if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+               return false;
+       for(i = 0; i < subframe->order; i++)
+               if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
+                       return false;
+
+       if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
+               return false;
+       switch(subframe->entropy_coding_method.type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!add_residual_partitioned_rice_(
+                               bw,
+                               subframe->residual,
+                               residual_samples,
+                               subframe->order,
+                               subframe->entropy_coding_method.data.partitioned_rice.contents->parameters,
+                               subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits,
+                               subframe->entropy_coding_method.data.partitioned_rice.order,
+                               /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
+                       ))
+                               return false;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+
+       return true;
+}
+
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+       unsigned i;
+       const FLAC__int32 *signal = subframe->data;
+
+       if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+               return false;
+       if(wasted_bits)
+               if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+                       return false;
+
+       for(i = 0; i < samples; i++)
+               if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
+                       return false;
+
+       return true;
+}
+
+FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
+{
+       if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+               return false;
+       switch(method->type) {
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+               case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+                               return false;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+       }
+       return true;
+}
+
+FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended)
+{
+       const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+       const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+       if(partition_order == 0) {
+               unsigned i;
+
+               if(raw_bits[0] == 0) {
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen))
+                               return false;
+                       if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0]))
+                               return false;
+               }
+               else {
+                       FLAC__ASSERT(rice_parameters[0] == 0);
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
+                               return false;
+                       if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+                               return false;
+                       for(i = 0; i < residual_samples; i++) {
+                               if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
+                                       return false;
+                       }
+               }
+               return true;
+       }
+       else {
+               unsigned i, j, k = 0, k_last = 0;
+               unsigned partition_samples;
+               const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order;
+               for(i = 0; i < (1u<<partition_order); i++) {
+                       partition_samples = default_partition_samples;
+                       if(i == 0)
+                               partition_samples -= predictor_order;
+                       k += partition_samples;
+                       if(raw_bits[i] == 0) {
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], plen))
+                                       return false;
+                               if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i]))
+                                       return false;
+                       }
+                       else {
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
+                                       return false;
+                               if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+                                       return false;
+                               for(j = k_last; j < k; j++) {
+                                       if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
+                                               return false;
+                               }
+                       }
+                       k_last = k;
+               }
+               return true;
+       }
+}
diff --git a/src/libFLAC/window.c b/src/libFLAC/window.c
new file mode 100644 (file)
index 0000000..cd689c5
--- /dev/null
@@ -0,0 +1,225 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006,2007  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#ifndef M_PI
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_PI 3.14159265358979323846
+#endif
+
+
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       if (L & 1) {
+               for (n = 0; n <= N/2; n++)
+                       window[n] = 2.0f * n / (float)N;
+               for (; n <= N; n++)
+                       window[n] = 2.0f - 2.0f * n / (float)N;
+       }
+       else {
+               for (n = 0; n <= L/2-1; n++)
+                       window[n] = 2.0f * n / (float)N;
+               for (; n <= N; n++)
+                       window[n] = 2.0f - 2.0f * (N-n) / (float)N;
+       }
+}
+
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f)));
+}
+
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
+}
+
+/* 4-term -92dB side-lobe */
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n <= N; n++)
+               window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       const double N2 = (double)N / 2.;
+       FLAC__int32 n;
+
+       for (n = 0; n <= N; n++) {
+               double k = ((double)n - N2) / N2;
+               k = 1.0f - k * k;
+               window[n] = (FLAC__real)(k * k);
+       }
+}
+
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N));
+}
+
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
+{
+       const FLAC__int32 N = L - 1;
+       const double N2 = (double)N / 2.;
+       FLAC__int32 n;
+
+       for (n = 0; n <= N; n++) {
+               const double k = ((double)n - N2) / (stddev * N2);
+               window[n] = (FLAC__real)exp(-0.5f * k * k);
+       }
+}
+
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
+}
+
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
+{
+       FLAC__int32 n;
+
+       for (n = 0; n < L; n++)
+               window[n] = 1.0f;
+}
+
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
+{
+       FLAC__int32 n;
+
+       if (L & 1) {
+               for (n = 1; n <= L+1/2; n++)
+                       window[n-1] = 2.0f * n / ((float)L + 1.0f);
+               for (; n <= L; n++)
+                       window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+       }
+       else {
+               for (n = 1; n <= L/2; n++)
+                       window[n-1] = 2.0f * n / (float)L;
+               for (; n <= L; n++)
+                       window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L;
+       }
+}
+
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
+{
+       if (p <= 0.0)
+               FLAC__window_rectangle(window, L);
+       else if (p >= 1.0)
+               FLAC__window_hann(window, L);
+       else {
+               const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
+               FLAC__int32 n;
+               /* start with rectangle... */
+               FLAC__window_rectangle(window, L);
+               /* ...replace ends with hann */
+               if (Np > 0) {
+                       for (n = 0; n <= Np; n++) {
+                               window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
+                               window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
+                       }
+               }
+       }
+}
+
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
+{
+       const FLAC__int32 N = L - 1;
+       const double N2 = (double)N / 2.;
+       FLAC__int32 n;
+
+       for (n = 0; n <= N; n++) {
+               const double k = ((double)n - N2) / N2;
+               window[n] = (FLAC__real)(1.0f - k * k);
+       }
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/metaflac/Makefile.am b/src/metaflac/Makefile.am
new file mode 100644 (file)
index 0000000..92aa50b
--- /dev/null
@@ -0,0 +1,54 @@
+#  metaflac - Command-line FLAC metadata editor
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+bin_PROGRAMS = metaflac
+
+AM_CFLAGS = @OGG_CFLAGS@
+
+EXTRA_DIST = \
+       Makefile.lite \
+       metaflac.dsp \
+       metaflac.vcproj
+
+metaflac_SOURCES = \
+       main.c \
+       operations.c \
+       operations_shorthand_cuesheet.c \
+       operations_shorthand_picture.c \
+       operations_shorthand_seektable.c \
+       operations_shorthand_streaminfo.c \
+       operations_shorthand_vorbiscomment.c \
+       options.c \
+       usage.c \
+       utils.c \
+       operations.h \
+       operations_shorthand.h \
+       options.h \
+       usage.h \
+       utils.h
+metaflac_LDFLAGS = 
+
+metaflac_LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/share/getopt/libgetopt.a \
+       $(top_builddir)/src/share/utf8/libutf8.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @LIBICONV@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
diff --git a/src/metaflac/Makefile.lite b/src/metaflac/Makefile.lite
new file mode 100644 (file)
index 0000000..56dba51
--- /dev/null
@@ -0,0 +1,49 @@
+#  metaflac - Command-line FLAC metadata editor
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = metaflac
+
+INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR)
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(libdir)/libgetopt.a $(libdir)/libutf8.a $(OGG_LIB_DIR)/libogg.a -liconv -lm
+else
+LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lgetopt -lutf8 -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       main.c \
+       operations.c \
+       operations_shorthand_cuesheet.c \
+       operations_shorthand_picture.c \
+       operations_shorthand_seektable.c \
+       operations_shorthand_streaminfo.c \
+       operations_shorthand_vorbiscomment.c \
+       options.c \
+       usage.c \
+       utils.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/metaflac/main.c b/src/metaflac/main.c
new file mode 100644 (file)
index 0000000..d2b8145
--- /dev/null
@@ -0,0 +1,48 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "operations.h"
+#include "options.h"
+#include <locale.h>
+
+int main(int argc, char *argv[])
+{
+       CommandLineOptions options;
+       int ret = 0;
+
+#ifdef __EMX__
+       _response(&argc, &argv);
+       _wildcard(&argc, &argv);
+#endif
+
+       setlocale(LC_ALL, "");
+       init_options(&options);
+
+       if(parse_options(argc, argv, &options))
+               ret = !do_operations(&options);
+       else
+               ret = 1;
+
+       free_options(&options);
+
+       return ret;
+}
diff --git a/src/metaflac/metaflac.dsp b/src/metaflac/metaflac.dsp
new file mode 100644 (file)
index 0000000..763bb68
--- /dev/null
@@ -0,0 +1,152 @@
+# Microsoft Developer Studio Project File - Name="metaflac" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=metaflac - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "metaflac.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "metaflac.mak" CFG="metaflac - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "metaflac - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "metaflac - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "metaflac - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\obj\release\lib\getopt_static.lib ..\..\obj\release\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "metaflac - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\grabbag_static.lib ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\obj\debug\lib\getopt_static.lib ..\..\obj\debug\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "metaflac - Win32 Release"\r
+# Name "metaflac - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations_shorthand_cuesheet.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations_shorthand_picture.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations_shorthand_seektable.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations_shorthand_streaminfo.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\operations_shorthand_vorbiscomment.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\options.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\usage.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utils.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\operations.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\options.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\usage.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utils.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/metaflac/metaflac.vcproj b/src/metaflac/metaflac.vcproj
new file mode 100644 (file)
index 0000000..bbaa042
--- /dev/null
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="metaflac"\r
+       ProjectGUID="{4cefbc87-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="metaflac"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\operations.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\options.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\usage.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\utils.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations_shorthand_cuesheet.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations_shorthand_picture.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations_shorthand_seektable.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations_shorthand_streaminfo.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\operations_shorthand_vorbiscomment.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\options.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\usage.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\utils.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c
new file mode 100644 (file)
index 0000000..54774bf
--- /dev/null
@@ -0,0 +1,682 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "operations.h"
+#include "usage.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "operations_shorthand.h"
+
+static void show_version(void);
+static FLAC__bool do_major_operation(const CommandLineOptions *options);
+static FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operations(const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options);
+static FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert);
+static FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime);
+static FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write);
+
+static FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number);
+static void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application);
+
+/* from operations_shorthand_seektable.c */
+extern FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write);
+
+/* from operations_shorthand_streaminfo.c */
+extern FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+/* from operations_shorthand_vorbiscomment.c */
+extern FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw);
+
+/* from operations_shorthand_cuesheet.c */
+extern FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+/* from operations_shorthand_picture.c */
+extern FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+
+
+FLAC__bool do_operations(const CommandLineOptions *options)
+{
+       FLAC__bool ok = true;
+
+       if(options->show_long_help) {
+               long_usage(0);
+       }
+       if(options->show_version) {
+               show_version();
+       }
+       else if(options->args.checks.num_major_ops > 0) {
+               FLAC__ASSERT(options->args.checks.num_shorthand_ops == 0);
+               FLAC__ASSERT(options->args.checks.num_major_ops == 1);
+               FLAC__ASSERT(options->args.checks.num_major_ops == options->ops.num_operations);
+               ok = do_major_operation(options);
+       }
+       else if(options->args.checks.num_shorthand_ops > 0) {
+               FLAC__ASSERT(options->args.checks.num_shorthand_ops == options->ops.num_operations);
+               ok = do_shorthand_operations(options);
+       }
+
+       return ok;
+}
+
+/*
+ * local routines
+ */
+
+void show_version(void)
+{
+       printf("metaflac %s\n", FLAC__VERSION_STRING);
+}
+
+FLAC__bool do_major_operation(const CommandLineOptions *options)
+{
+       unsigned i;
+       FLAC__bool ok = true;
+
+       /* to die after first error,     v---  add '&& ok' here */
+       for(i = 0; i < options->num_files; i++)
+               ok &= do_major_operation_on_file(options->filenames[i], options);
+
+       return ok;
+}
+
+FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options)
+{
+       FLAC__bool ok = true, needs_write = false, is_ogg = false;
+       FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+
+       if(0 == chain)
+               die("out of memory allocating chain");
+
+       /*@@@@ lame way of guessing the file type */
+       if(strlen(filename) >= 4 && (0 == strcmp(filename+strlen(filename)-4, ".oga") || 0 == strcmp(filename+strlen(filename)-4, ".ogg")))
+               is_ogg = true;
+
+       if(! (is_ogg? FLAC__metadata_chain_read_ogg(chain, filename) : FLAC__metadata_chain_read(chain, filename)) ) {
+               print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
+               FLAC__metadata_chain_delete(chain);
+               return false;
+       }
+
+       switch(options->ops.operations[0].type) {
+               case OP__LIST:
+                       ok = do_major_operation__list(options->prefix_with_filename? filename : 0, chain, options);
+                       break;
+               case OP__APPEND:
+                       ok = do_major_operation__append(chain, options);
+                       needs_write = true;
+                       break;
+               case OP__REMOVE:
+                       ok = do_major_operation__remove(chain, options);
+                       needs_write = true;
+                       break;
+               case OP__REMOVE_ALL:
+                       ok = do_major_operation__remove_all(chain, options);
+                       needs_write = true;
+                       break;
+               case OP__MERGE_PADDING:
+                       FLAC__metadata_chain_merge_padding(chain);
+                       needs_write = true;
+                       break;
+               case OP__SORT_PADDING:
+                       FLAC__metadata_chain_sort_padding(chain);
+                       needs_write = true;
+                       break;
+               default:
+                       FLAC__ASSERT(0);
+                       return false;
+       }
+
+       if(ok && needs_write) {
+               if(options->use_padding)
+                       FLAC__metadata_chain_sort_padding(chain);
+               ok = FLAC__metadata_chain_write(chain, options->use_padding, options->preserve_modtime);
+               if(!ok)
+                       print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
+       }
+
+       FLAC__metadata_chain_delete(chain);
+
+       return ok;
+}
+
+FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+       FLAC__StreamMetadata *block;
+       FLAC__bool ok = true;
+       unsigned block_number;
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       block_number = 0;
+       do {
+               block = FLAC__metadata_iterator_get_block(iterator);
+               ok &= (0 != block);
+               if(!ok)
+                       fprintf(stderr, "%s: ERROR: couldn't get block from chain\n", filename);
+               else if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number))
+                       write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump);
+               block_number++;
+       } while(ok && FLAC__metadata_iterator_next(iterator));
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       return ok;
+}
+
+FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+       (void) chain, (void) options;
+       fprintf(stderr, "ERROR: --append not implemented yet\n");
+       return false;
+}
+
+FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+       FLAC__bool ok = true;
+       unsigned block_number;
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       block_number = 0;
+       while(ok && FLAC__metadata_iterator_next(iterator)) {
+               block_number++;
+               if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number)) {
+                       ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
+                       if(options->use_padding)
+                               ok &= FLAC__metadata_iterator_next(iterator);
+               }
+       }
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       return ok;
+}
+
+FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
+{
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+       FLAC__bool ok = true;
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       while(ok && FLAC__metadata_iterator_next(iterator)) {
+               ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
+               if(options->use_padding)
+                       ok &= FLAC__metadata_iterator_next(iterator);
+       }
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       return ok;
+}
+
+FLAC__bool do_shorthand_operations(const CommandLineOptions *options)
+{
+       unsigned i;
+       FLAC__bool ok = true;
+
+       /* to die after first error,     v---  add '&& ok' here */
+       for(i = 0; i < options->num_files; i++)
+               ok &= do_shorthand_operations_on_file(options->filenames[i], options);
+
+       /* check if OP__ADD_REPLAY_GAIN requested */
+       if(ok && options->num_files > 0) {
+               for(i = 0; i < options->ops.num_operations; i++) {
+                       if(options->ops.operations[i].type == OP__ADD_REPLAY_GAIN)
+                               ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime);
+               }
+       }
+
+       return ok;
+}
+
+FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options)
+{
+       unsigned i;
+       FLAC__bool ok = true, needs_write = false, use_padding = options->use_padding;
+       FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+
+       if(0 == chain)
+               die("out of memory allocating chain");
+
+       if(!FLAC__metadata_chain_read(chain, filename)) {
+               print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
+               return false;
+       }
+
+       for(i = 0; i < options->ops.num_operations && ok; i++) {
+               /*
+                * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
+                * --add-seekpoint and --import-cuesheet-from are used.
+                */
+               if(options->ops.operations[i].type != OP__ADD_SEEKPOINT)
+                       ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
+
+               /* The following seems counterintuitive but the meaning
+                * of 'use_padding' is 'try to keep the overall metadata
+                * to its original size, adding or truncating extra
+                * padding if necessary' which is why we need to turn it
+                * off in this case.  If we don't, the extra padding block
+                * will just be truncated.
+                */
+               if(options->ops.operations[i].type == OP__ADD_PADDING)
+                       use_padding = false;
+       }
+
+       /*
+        * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
+        * --add-seekpoint and --import-cuesheet-from are used.
+        */
+       for(i = 0; i < options->ops.num_operations && ok; i++) {
+               if(options->ops.operations[i].type == OP__ADD_SEEKPOINT)
+                       ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
+       }
+
+       if(ok && needs_write) {
+               if(use_padding)
+                       FLAC__metadata_chain_sort_padding(chain);
+               ok = FLAC__metadata_chain_write(chain, use_padding, options->preserve_modtime);
+               if(!ok)
+                       print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
+       }
+
+       FLAC__metadata_chain_delete(chain);
+
+       return ok;
+}
+
+FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert)
+{
+       FLAC__bool ok = true;
+
+       switch(operation->type) {
+               case OP__SHOW_MD5SUM:
+               case OP__SHOW_MIN_BLOCKSIZE:
+               case OP__SHOW_MAX_BLOCKSIZE:
+               case OP__SHOW_MIN_FRAMESIZE:
+               case OP__SHOW_MAX_FRAMESIZE:
+               case OP__SHOW_SAMPLE_RATE:
+               case OP__SHOW_CHANNELS:
+               case OP__SHOW_BPS:
+               case OP__SHOW_TOTAL_SAMPLES:
+               case OP__SET_MD5SUM:
+               case OP__SET_MIN_BLOCKSIZE:
+               case OP__SET_MAX_BLOCKSIZE:
+               case OP__SET_MIN_FRAMESIZE:
+               case OP__SET_MAX_FRAMESIZE:
+               case OP__SET_SAMPLE_RATE:
+               case OP__SET_CHANNELS:
+               case OP__SET_BPS:
+               case OP__SET_TOTAL_SAMPLES:
+                       ok = do_shorthand_operation__streaminfo(filename, prefix_with_filename, chain, operation, needs_write);
+                       break;
+               case OP__SHOW_VC_VENDOR:
+               case OP__SHOW_VC_FIELD:
+               case OP__REMOVE_VC_ALL:
+               case OP__REMOVE_VC_FIELD:
+               case OP__REMOVE_VC_FIRSTFIELD:
+               case OP__SET_VC_FIELD:
+               case OP__IMPORT_VC_FROM:
+               case OP__EXPORT_VC_TO:
+                       ok = do_shorthand_operation__vorbis_comment(filename, prefix_with_filename, chain, operation, needs_write, !utf8_convert);
+                       break;
+               case OP__IMPORT_CUESHEET_FROM:
+               case OP__EXPORT_CUESHEET_TO:
+                       ok = do_shorthand_operation__cuesheet(filename, chain, operation, needs_write);
+                       break;
+               case OP__IMPORT_PICTURE_FROM:
+               case OP__EXPORT_PICTURE_TO:
+                       ok = do_shorthand_operation__picture(filename, chain, operation, needs_write);
+                       break;
+               case OP__ADD_SEEKPOINT:
+                       ok = do_shorthand_operation__add_seekpoints(filename, chain, operation->argument.add_seekpoint.specification, needs_write);
+                       break;
+               case OP__ADD_REPLAY_GAIN:
+                       /* this command is always executed last */
+                       ok = true;
+                       break;
+               case OP__ADD_PADDING:
+                       ok = do_shorthand_operation__add_padding(filename, chain, operation->argument.add_padding.length, needs_write);
+                       break;
+               default:
+                       ok = false;
+                       FLAC__ASSERT(0);
+                       break;
+       };
+
+       return ok;
+}
+
+FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime)
+{
+       FLAC__StreamMetadata streaminfo;
+       float *title_gains = 0, *title_peaks = 0;
+       float album_gain, album_peak;
+       unsigned sample_rate = 0;
+       unsigned bits_per_sample = 0;
+       unsigned channels = 0;
+       unsigned i;
+       const char *error;
+       FLAC__bool first = true;
+
+       FLAC__ASSERT(num_files > 0);
+
+       for(i = 0; i < num_files; i++) {
+               FLAC__ASSERT(0 != filenames[i]);
+               if(!FLAC__metadata_get_streaminfo(filenames[i], &streaminfo)) {
+                       fprintf(stderr, "%s: ERROR: can't open file or get STREAMINFO block\n", filenames[i]);
+                       return false;
+               }
+               if(first) {
+                       first = false;
+                       sample_rate = streaminfo.data.stream_info.sample_rate;
+                       bits_per_sample = streaminfo.data.stream_info.bits_per_sample;
+                       channels = streaminfo.data.stream_info.channels;
+               }
+               else {
+                       if(sample_rate != streaminfo.data.stream_info.sample_rate) {
+                               fprintf(stderr, "%s: ERROR: sample rate of %u Hz does not match previous files' %u Hz\n", filenames[i], streaminfo.data.stream_info.sample_rate, sample_rate);
+                               return false;
+                       }
+                       if(bits_per_sample != streaminfo.data.stream_info.bits_per_sample) {
+                               fprintf(stderr, "%s: ERROR: resolution of %u bps does not match previous files' %u bps\n", filenames[i], streaminfo.data.stream_info.bits_per_sample, bits_per_sample);
+                               return false;
+                       }
+                       if(channels != streaminfo.data.stream_info.channels) {
+                               fprintf(stderr, "%s: ERROR: # channels (%u) does not match previous files' (%u)\n", filenames[i], streaminfo.data.stream_info.channels, channels);
+                               return false;
+                       }
+               }
+               if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
+                       fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supported\n", filenames[i], sample_rate);
+                       return false;
+               }
+               if(channels != 1 && channels != 2) {
+                       fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2\n", filenames[i], channels);
+                       return false;
+               }
+       }
+       FLAC__ASSERT(bits_per_sample >= FLAC__MIN_BITS_PER_SAMPLE && bits_per_sample <= FLAC__MAX_BITS_PER_SAMPLE);
+
+       if(!grabbag__replaygain_init(sample_rate)) {
+               FLAC__ASSERT(0);
+               /* double protection */
+               fprintf(stderr, "internal error\n");
+               return false;
+       }
+
+       if(
+               0 == (title_gains = (float*)safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) ||
+               0 == (title_peaks = (float*)safe_malloc_mul_2op_(sizeof(float), /*times*/num_files))
+       )
+               die("out of memory allocating space for title gains/peaks");
+
+       for(i = 0; i < num_files; i++) {
+               if(0 != (error = grabbag__replaygain_analyze_file(filenames[i], title_gains+i, title_peaks+i))) {
+                       fprintf(stderr, "%s: ERROR: during analysis (%s)\n", filenames[i], error);
+                       free(title_gains);
+                       free(title_peaks);
+                       return false;
+               }
+       }
+       grabbag__replaygain_get_album(&album_gain, &album_peak);
+
+       for(i = 0; i < num_files; i++) {
+               if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) {
+                       fprintf(stderr, "%s: ERROR: writing tags (%s)\n", filenames[i], error);
+                       free(title_gains);
+                       free(title_peaks);
+                       return false;
+               }
+       }
+
+       free(title_gains);
+       free(title_peaks);
+       return true;
+}
+
+FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write)
+{
+       FLAC__StreamMetadata *padding = 0;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       while(FLAC__metadata_iterator_next(iterator))
+               ;
+
+       padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+       if(0 == padding)
+               die("out of memory allocating PADDING block");
+
+       padding->length = length;
+
+       if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) {
+               print_error_with_chain_status(chain, "%s: ERROR: adding new PADDING block to metadata", filename);
+               FLAC__metadata_object_delete(padding);
+               FLAC__metadata_iterator_delete(iterator);
+               return false;
+       }
+
+       FLAC__metadata_iterator_delete(iterator);
+       *needs_write = true;
+       return true;
+}
+
+FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number)
+{
+       unsigned i, j;
+       FLAC__bool matches_number = false, matches_type = false;
+       FLAC__bool has_block_number_arg = false;
+
+       for(i = 0; i < options->args.num_arguments; i++) {
+               if(options->args.arguments[i].type == ARG__BLOCK_TYPE || options->args.arguments[i].type == ARG__EXCEPT_BLOCK_TYPE) {
+                       for(j = 0; j < options->args.arguments[i].value.block_type.num_entries; j++) {
+                               if(options->args.arguments[i].value.block_type.entries[j].type == block->type) {
+                                       if(block->type != FLAC__METADATA_TYPE_APPLICATION || !options->args.arguments[i].value.block_type.entries[j].filter_application_by_id || 0 == memcmp(options->args.arguments[i].value.block_type.entries[j].application_id, block->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+                                               matches_type = true;
+                               }
+                       }
+               }
+               else if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) {
+                       has_block_number_arg = true;
+                       for(j = 0; j < options->args.arguments[i].value.block_number.num_entries; j++) {
+                               if(options->args.arguments[i].value.block_number.entries[j] == block_number)
+                                       matches_number = true;
+                       }
+               }
+       }
+
+       if(!has_block_number_arg)
+               matches_number = true;
+
+       if(options->args.checks.has_block_type) {
+               FLAC__ASSERT(!options->args.checks.has_except_block_type);
+       }
+       else if(options->args.checks.has_except_block_type)
+               matches_type = !matches_type;
+       else
+               matches_type = true;
+
+       return matches_number && matches_type;
+}
+
+void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application)
+{
+       unsigned i, j;
+
+/*@@@ yuck, should do this with a varargs function or something: */
+#define PPR if(filename)printf("%s:",filename);
+       PPR; printf("METADATA block #%u\n", block_number);
+       PPR; printf("  type: %u (%s)\n", (unsigned)block->type, block->type < FLAC__METADATA_TYPE_UNDEFINED? FLAC__MetadataTypeString[block->type] : "UNKNOWN");
+       PPR; printf("  is last: %s\n", block->is_last? "true":"false");
+       PPR; printf("  length: %u\n", block->length);
+
+       switch(block->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       PPR; printf("  minimum blocksize: %u samples\n", block->data.stream_info.min_blocksize);
+                       PPR; printf("  maximum blocksize: %u samples\n", block->data.stream_info.max_blocksize);
+                       PPR; printf("  minimum framesize: %u bytes\n", block->data.stream_info.min_framesize);
+                       PPR; printf("  maximum framesize: %u bytes\n", block->data.stream_info.max_framesize);
+                       PPR; printf("  sample_rate: %u Hz\n", block->data.stream_info.sample_rate);
+                       PPR; printf("  channels: %u\n", block->data.stream_info.channels);
+                       PPR; printf("  bits-per-sample: %u\n", block->data.stream_info.bits_per_sample);
+#ifdef _MSC_VER
+                       PPR; printf("  total samples: %I64u\n", block->data.stream_info.total_samples);
+#else
+                       PPR; printf("  total samples: %llu\n", (unsigned long long)block->data.stream_info.total_samples);
+#endif
+                       PPR; printf("  MD5 signature: ");
+                       for(i = 0; i < 16; i++) {
+                               printf("%02x", (unsigned)block->data.stream_info.md5sum[i]);
+                       }
+                       printf("\n");
+                       break;
+               case FLAC__METADATA_TYPE_PADDING:
+                       /* nothing to print */
+                       break;
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       PPR; printf("  application ID: ");
+                       for(i = 0; i < 4; i++)
+                               printf("%02x", block->data.application.id[i]);
+                       printf("\n");
+                       PPR; printf("  data contents:\n");
+                       if(0 != block->data.application.data) {
+                               if(hexdump_application)
+                                       hexdump(filename, block->data.application.data, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, "    ");
+                               else
+                                       (void) local_fwrite(block->data.application.data, 1, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, stdout);
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       PPR; printf("  seek points: %u\n", block->data.seek_table.num_points);
+                       for(i = 0; i < block->data.seek_table.num_points; i++) {
+                               if(block->data.seek_table.points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+#ifdef _MSC_VER
+                                       PPR; printf("    point %u: sample_number=%I64u, stream_offset=%I64u, frame_samples=%u\n", i, block->data.seek_table.points[i].sample_number, block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples);
+#else
+                                       PPR; printf("    point %u: sample_number=%llu, stream_offset=%llu, frame_samples=%u\n", i, (unsigned long long)block->data.seek_table.points[i].sample_number, (unsigned long long)block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples);
+#endif
+                               }
+                               else {
+                                       PPR; printf("    point %u: PLACEHOLDER\n", i);
+                               }
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       PPR; printf("  vendor string: ");
+                       write_vc_field(0, &block->data.vorbis_comment.vendor_string, raw, stdout);
+                       PPR; printf("  comments: %u\n", block->data.vorbis_comment.num_comments);
+                       for(i = 0; i < block->data.vorbis_comment.num_comments; i++) {
+                               PPR; printf("    comment[%u]: ", i);
+                               write_vc_field(0, &block->data.vorbis_comment.comments[i], raw, stdout);
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       PPR; printf("  media catalog number: %s\n", block->data.cue_sheet.media_catalog_number);
+#ifdef _MSC_VER
+                       PPR; printf("  lead-in: %I64u\n", block->data.cue_sheet.lead_in);
+#else
+                       PPR; printf("  lead-in: %llu\n", (unsigned long long)block->data.cue_sheet.lead_in);
+#endif
+                       PPR; printf("  is CD: %s\n", block->data.cue_sheet.is_cd? "true":"false");
+                       PPR; printf("  number of tracks: %u\n", block->data.cue_sheet.num_tracks);
+                       for(i = 0; i < block->data.cue_sheet.num_tracks; i++) {
+                               const FLAC__StreamMetadata_CueSheet_Track *track = block->data.cue_sheet.tracks+i;
+                               const FLAC__bool is_last = (i == block->data.cue_sheet.num_tracks-1);
+                               const FLAC__bool is_leadout = is_last && track->num_indices == 0;
+                               PPR; printf("    track[%u]\n", i);
+#ifdef _MSC_VER
+                               PPR; printf("      offset: %I64u\n", track->offset);
+#else
+                               PPR; printf("      offset: %llu\n", (unsigned long long)track->offset);
+#endif
+                               if(is_last) {
+                                       PPR; printf("      number: %u (%s)\n", (unsigned)track->number, is_leadout? "LEAD-OUT" : "INVALID");
+                               }
+                               else {
+                                       PPR; printf("      number: %u\n", (unsigned)track->number);
+                               }
+                               if(!is_leadout) {
+                                       PPR; printf("      ISRC: %s\n", track->isrc);
+                                       PPR; printf("      type: %s\n", track->type == 1? "DATA" : "AUDIO");
+                                       PPR; printf("      pre-emphasis: %s\n", track->pre_emphasis? "true":"false");
+                                       PPR; printf("      number of index points: %u\n", track->num_indices);
+                                       for(j = 0; j < track->num_indices; j++) {
+                                               const FLAC__StreamMetadata_CueSheet_Index *index = track->indices+j;
+                                               PPR; printf("        index[%u]\n", j);
+#ifdef _MSC_VER
+                                               PPR; printf("          offset: %I64u\n", index->offset);
+#else
+                                               PPR; printf("          offset: %llu\n", (unsigned long long)index->offset);
+#endif
+                                               PPR; printf("          number: %u\n", (unsigned)index->number);
+                                       }
+                               }
+                       }
+                       break;
+               case FLAC__METADATA_TYPE_PICTURE:
+                       PPR; printf("  type: %u (%s)\n", block->data.picture.type, block->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? FLAC__StreamMetadata_Picture_TypeString[block->data.picture.type] : "UNDEFINED");
+                       PPR; printf("  MIME type: %s\n", block->data.picture.mime_type);
+                       PPR; printf("  description: %s\n", block->data.picture.description);
+                       PPR; printf("  width: %u\n", (unsigned)block->data.picture.width);
+                       PPR; printf("  height: %u\n", (unsigned)block->data.picture.height);
+                       PPR; printf("  depth: %u\n", (unsigned)block->data.picture.depth);
+                       PPR; printf("  colors: %u%s\n", (unsigned)block->data.picture.colors, block->data.picture.colors? "" : " (unindexed)");
+                       PPR; printf("  data length: %u\n", (unsigned)block->data.picture.data_length);
+                       PPR; printf("  data:\n");
+                       if(0 != block->data.picture.data)
+                               hexdump(filename, block->data.picture.data, block->data.picture.data_length, "    ");
+                       break;
+               default:
+                       PPR; printf("  data contents:\n");
+                       if(0 != block->data.unknown.data)
+                               hexdump(filename, block->data.unknown.data, block->length, "    ");
+                       break;
+       }
+#undef PPR
+}
diff --git a/src/metaflac/operations.h b/src/metaflac/operations.h
new file mode 100644 (file)
index 0000000..b5144a3
--- /dev/null
@@ -0,0 +1,26 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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 metaflac__operations_h
+#define metaflac__operations_h
+
+#include "options.h"
+
+FLAC__bool do_operations(const CommandLineOptions *options);
+
+#endif
diff --git a/src/metaflac/operations_shorthand.h b/src/metaflac/operations_shorthand.h
new file mode 100644 (file)
index 0000000..112c079
--- /dev/null
@@ -0,0 +1,25 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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 "options.h"
+
+FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
+FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw);
diff --git a/src/metaflac/operations_shorthand_cuesheet.c b/src/metaflac/operations_shorthand_cuesheet.c
new file mode 100644 (file)
index 0000000..14912c1
--- /dev/null
@@ -0,0 +1,217 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h> /* for snprintf() */
+#include <string.h>
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+#include "operations_shorthand.h"
+
+static FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link);
+static FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename);
+
+FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+       FLAC__bool ok = true;
+       FLAC__StreamMetadata *cuesheet = 0;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+       FLAC__uint64 lead_out_offset = 0;
+       FLAC__bool is_cdda = false;
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       do {
+               FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+               if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+                       lead_out_offset = block->data.stream_info.total_samples;
+                       if(lead_out_offset == 0) {
+                               fprintf(stderr, "%s: ERROR: FLAC file must have total_samples set in STREAMINFO in order to import/export cuesheet\n", filename);
+                               FLAC__metadata_iterator_delete(iterator);
+                               return false;
+                       }
+                       is_cdda = (block->data.stream_info.channels == 1 || block->data.stream_info.channels == 2) && (block->data.stream_info.bits_per_sample == 16) && (block->data.stream_info.sample_rate == 44100);
+               }
+               else if(block->type == FLAC__METADATA_TYPE_CUESHEET)
+                       cuesheet = block;
+       } while(FLAC__metadata_iterator_next(iterator));
+
+       if(lead_out_offset == 0) {
+               fprintf(stderr, "%s: ERROR: FLAC stream has no STREAMINFO block\n", filename);
+               FLAC__metadata_iterator_delete(iterator);
+               return false;
+       }
+
+       switch(operation->type) {
+               case OP__IMPORT_CUESHEET_FROM:
+                       if(0 != cuesheet) {
+                               fprintf(stderr, "%s: ERROR: FLAC file already has CUESHEET block\n", filename);
+                               ok = false;
+                       }
+                       else {
+                               ok = import_cs_from(filename, &cuesheet, operation->argument.import_cuesheet_from.filename, needs_write, lead_out_offset, is_cdda, operation->argument.import_cuesheet_from.add_seekpoint_link);
+                               if(ok) {
+                                       /* append CUESHEET block */
+                                       while(FLAC__metadata_iterator_next(iterator))
+                                               ;
+                                       if(!FLAC__metadata_iterator_insert_block_after(iterator, cuesheet)) {
+                                               print_error_with_chain_status(chain, "%s: ERROR: adding new CUESHEET block to metadata", filename);
+                                               FLAC__metadata_object_delete(cuesheet);
+                                               ok = false;
+                                       }
+                               }
+                       }
+                       break;
+               case OP__EXPORT_CUESHEET_TO:
+                       if(0 == cuesheet) {
+                               fprintf(stderr, "%s: ERROR: FLAC file has no CUESHEET block\n", filename);
+                               ok = false;
+                       }
+                       else
+                               ok = export_cs_to(filename, cuesheet, operation->argument.filename.value);
+                       break;
+               default:
+                       ok = false;
+                       FLAC__ASSERT(0);
+                       break;
+       };
+
+       FLAC__metadata_iterator_delete(iterator);
+       return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link)
+{
+       FILE *f;
+       const char *error_message;
+       char **seekpoint_specification = add_seekpoint_link? &(add_seekpoint_link->specification) : 0;
+       unsigned last_line_read;
+
+       if(0 == cs_filename || strlen(cs_filename) == 0) {
+               fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+               return false;
+       }
+       if(0 == strcmp(cs_filename, "-"))
+               f = stdin;
+       else
+               f = fopen(cs_filename, "r");
+
+       if(0 == f) {
+               fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, cs_filename, strerror(errno));
+               return false;
+       }
+
+       *cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, is_cdda, lead_out_offset);
+
+       if(f != stdin)
+               fclose(f);
+
+       if(0 == *cuesheet) {
+               fprintf(stderr, "%s: ERROR: while parsing cuesheet \"%s\" on line %u: %s\n", filename, cs_filename, last_line_read, error_message);
+               return false;
+       }
+
+       if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) {
+               fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\": %s\n", filename, cs_filename, error_message);
+               return false;
+       }
+
+       /* if we're expecting CDDA, warn about non-compliance */
+       if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) {
+               fprintf(stderr, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", filename, cs_filename, error_message);
+               (*cuesheet)->data.cue_sheet.is_cd = false;
+       }
+
+       /* add seekpoints for each index point if required */
+       if(0 != seekpoint_specification) {
+               char spec[128];
+               unsigned track, index;
+               const FLAC__StreamMetadata_CueSheet *cs = &(*cuesheet)->data.cue_sheet;
+               if(0 == *seekpoint_specification)
+                       *seekpoint_specification = local_strdup("");
+               for(track = 0; track < cs->num_tracks; track++) {
+                       const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+track;
+                       for(index = 0; index < tr->num_indices; index++) {
+#ifdef _MSC_VER
+                               sprintf(spec, "%I64u;", tr->offset + tr->indices[index].offset);
+#else
+                               sprintf(spec, "%llu;", (unsigned long long)(tr->offset + tr->indices[index].offset));
+#endif
+                               local_strcat(seekpoint_specification, spec);
+                       }
+               }
+       }
+
+       *needs_write = true;
+       return true;
+}
+
+FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename)
+{
+       FILE *f;
+       char *ref = 0;
+       size_t reflen;
+
+       if(0 == cs_filename || strlen(cs_filename) == 0) {
+               fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+               return false;
+       }
+       if(0 == strcmp(cs_filename, "-"))
+               f = stdout;
+       else
+               f = fopen(cs_filename, "w");
+
+       if(0 == f) {
+               fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, cs_filename, strerror(errno));
+               return false;
+       }
+
+       reflen = strlen(filename) + 7 + 1;
+       if(0 == (ref = malloc(reflen))) {
+               fprintf(stderr, "%s: ERROR: allocating memory\n", filename);
+               return false;
+       }
+
+#if defined _MSC_VER || defined __MINGW32__
+       _snprintf(ref, reflen, "\"%s\" FLAC", filename);
+#else
+       snprintf(ref, reflen, "\"%s\" FLAC", filename);
+#endif
+
+       grabbag__cuesheet_emit(f, cuesheet, ref);
+
+       free(ref);
+
+       if(f != stdout)
+               fclose(f);
+
+       return true;
+}
diff --git a/src/metaflac/operations_shorthand_picture.c b/src/metaflac/operations_shorthand_picture.c
new file mode 100644 (file)
index 0000000..9045aae
--- /dev/null
@@ -0,0 +1,173 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h" /* for grabbag__picture_parse_specification() etc */
+
+#include "operations_shorthand.h"
+
+static FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write);
+static FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename);
+
+FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+       FLAC__bool ok = true, has_type1 = false, has_type2 = false;
+       FLAC__StreamMetadata *picture = 0;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       switch(operation->type) {
+               case OP__IMPORT_PICTURE_FROM:
+                       ok = import_pic_from(filename, &picture, operation->argument.specification.value, needs_write);
+                       if(ok) {
+                               /* append PICTURE block */
+                               while(FLAC__metadata_iterator_next(iterator))
+                                       ;
+                               if(!FLAC__metadata_iterator_insert_block_after(iterator, picture)) {
+                                       print_error_with_chain_status(chain, "%s: ERROR: adding new PICTURE block to metadata", filename);
+                                       FLAC__metadata_object_delete(picture);
+                                       ok = false;
+                               }
+                       }
+                       if(ok) {
+                               /* check global PICTURE constraints (max 1 block each of type=1 and type=2) */
+                               while(FLAC__metadata_iterator_prev(iterator))
+                                       ;
+                               do {
+                                       FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+                                       if(block->type == FLAC__METADATA_TYPE_PICTURE) {
+                                               if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+                                                       if(has_type1) {
+                                                               print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one 32x32 standard icon (type=1) PICTURE block", filename);
+                                                               ok = false;
+                                                       }
+                                                       has_type1 = true;
+                                               }
+                                               else if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+                                                       if(has_type2) {
+                                                               print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one icon (type=2) PICTURE block", filename);
+                                                               ok = false;
+                                                       }
+                                                       has_type2 = true;
+                                               }
+                                       }
+                               } while(FLAC__metadata_iterator_next(iterator));
+                       }
+                       break;
+               case OP__EXPORT_PICTURE_TO:
+                       {
+                               const Argument_BlockNumber *a = operation->argument.export_picture_to.block_number_link;
+                               int block_number = (a && a->num_entries > 0)? (int)a->entries[0] : -1;
+                               unsigned i = 0;
+                               do {
+                                       FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
+                                       if(block->type == FLAC__METADATA_TYPE_PICTURE && (block_number < 0 || i == (unsigned)block_number))
+                                               picture = block;
+                                       i++;
+                               } while(FLAC__metadata_iterator_next(iterator) && 0 == picture);
+                               if(0 == picture) {
+                                       if(block_number < 0)
+                                               fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block\n", filename);
+                                       else
+                                               fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block at block #%d\n", filename, block_number);
+                                       ok = false;
+                               }
+                               else
+                                       ok = export_pic_to(filename, picture, operation->argument.filename.value);
+                       }
+                       break;
+               default:
+                       ok = false;
+                       FLAC__ASSERT(0);
+                       break;
+       };
+
+       FLAC__metadata_iterator_delete(iterator);
+       return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write)
+{
+       const char *error_message;
+
+       if(0 == specification || strlen(specification) == 0) {
+               fprintf(stderr, "%s: ERROR: empty picture specification\n", filename);
+               return false;
+       }
+
+       *picture = grabbag__picture_parse_specification(specification, &error_message);
+
+       if(0 == *picture) {
+               fprintf(stderr, "%s: ERROR: while parsing picture specification \"%s\": %s\n", filename, specification, error_message);
+               return false;
+       }
+
+       if(!FLAC__format_picture_is_legal(&(*picture)->data.picture, &error_message)) {
+               fprintf(stderr, "%s: ERROR: new PICTURE block for \"%s\" is illegal: %s\n", filename, specification, error_message);
+               return false;
+       }
+
+       *needs_write = true;
+       return true;
+}
+
+FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename)
+{
+       FILE *f;
+       const FLAC__uint32 len = picture->data.picture.data_length;
+
+       if(0 == pic_filename || strlen(pic_filename) == 0) {
+               fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+               return false;
+       }
+       if(0 == strcmp(pic_filename, "-"))
+               f = grabbag__file_get_binary_stdout();
+       else
+               f = fopen(pic_filename, "wb");
+
+       if(0 == f) {
+               fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, pic_filename, strerror(errno));
+               return false;
+       }
+
+       if(fwrite(picture->data.picture.data, 1, len, f) != len) {
+               fprintf(stderr, "%s: ERROR: writing PICTURE data to file\n", filename);
+               return false;
+       }
+
+       if(f != stdout)
+               fclose(f);
+
+       return true;
+}
diff --git a/src/metaflac/operations_shorthand_seektable.c b/src/metaflac/operations_shorthand_seektable.c
new file mode 100644 (file)
index 0000000..4f4fb5d
--- /dev/null
@@ -0,0 +1,217 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+#include "operations_shorthand.h"
+
+static FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
+
+FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write)
+{
+       FLAC__bool ok = true, found_seektable_block = false;
+       FLAC__StreamMetadata *block = 0;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+       FLAC__uint64 total_samples = 0;
+       unsigned sample_rate = 0;
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       do {
+               block = FLAC__metadata_iterator_get_block(iterator);
+               if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+                       sample_rate = block->data.stream_info.sample_rate;
+                       total_samples = block->data.stream_info.total_samples;
+               }
+               else if(block->type == FLAC__METADATA_TYPE_SEEKTABLE)
+                       found_seektable_block = true;
+       } while(!found_seektable_block && FLAC__metadata_iterator_next(iterator));
+
+       if(total_samples == 0) {
+               fprintf(stderr, "%s: ERROR: cannot add seekpoints because STREAMINFO block does not specify total_samples\n", filename);
+               return false;
+       }
+
+       if(!found_seektable_block) {
+               /* create a new block */
+               block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+               if(0 == block)
+                       die("out of memory allocating SEEKTABLE block");
+               while(FLAC__metadata_iterator_prev(iterator))
+                       ;
+               if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) {
+                       print_error_with_chain_status(chain, "%s: ERROR: adding new SEEKTABLE block to metadata", filename);
+                       FLAC__metadata_object_delete(block);
+                       return false;
+               }
+               /* iterator is left pointing to new block */
+               FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block);
+       }
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       if(!grabbag__seektable_convert_specification_to_template(specification, /*only_explicit_placeholders=*/false, total_samples, sample_rate, block, /*spec_has_real_points=*/0)) {
+               fprintf(stderr, "%s: ERROR (internal) preparing seektable with seekpoints\n", filename);
+               return false;
+       }
+
+       ok = populate_seekpoint_values(filename, block, needs_write);
+
+       if(ok)
+               (void) FLAC__format_seektable_sort(&block->data.seek_table);
+
+       return ok;
+}
+
+/*
+ * local routines
+ */
+
+typedef struct {
+       FLAC__StreamMetadata_SeekTable *seektable_template;
+       FLAC__uint64 samples_written;
+       FLAC__uint64 audio_offset, last_offset;
+       unsigned first_seekpoint_to_check;
+       FLAC__bool error_occurred;
+       FLAC__StreamDecoderErrorStatus error_status;
+} ClientData;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       ClientData *cd = (ClientData*)client_data;
+
+       (void)buffer;
+       FLAC__ASSERT(0 != cd);
+
+       if(!cd->error_occurred) {
+               const unsigned blocksize = frame->header.blocksize;
+               const FLAC__uint64 frame_first_sample = cd->samples_written;
+               const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
+               FLAC__uint64 test_sample;
+               unsigned i;
+               for(i = cd->first_seekpoint_to_check; i < cd->seektable_template->num_points; i++) {
+                       test_sample = cd->seektable_template->points[i].sample_number;
+                       if(test_sample > frame_last_sample) {
+                               break;
+                       }
+                       else if(test_sample >= frame_first_sample) {
+                               cd->seektable_template->points[i].sample_number = frame_first_sample;
+                               cd->seektable_template->points[i].stream_offset = cd->last_offset - cd->audio_offset;
+                               cd->seektable_template->points[i].frame_samples = blocksize;
+                               cd->first_seekpoint_to_check++;
+                               /* DO NOT: "break;" and here's why:
+                                * The seektable template may contain more than one target
+                                * sample for any given frame; we will keep looping, generating
+                                * duplicate seekpoints for them, and we'll clean it up later,
+                                * just before writing the seektable back to the metadata.
+                                */
+                       }
+                       else {
+                               cd->first_seekpoint_to_check++;
+                       }
+               }
+               cd->samples_written += blocksize;
+               if(!FLAC__stream_decoder_get_decode_position(decoder, &cd->last_offset))
+                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+               return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+       }
+       else
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       ClientData *cd = (ClientData*)client_data;
+
+       (void)decoder;
+       FLAC__ASSERT(0 != cd);
+
+       if(!cd->error_occurred) { /* don't let multiple errors overwrite the first one */
+               cd->error_occurred = true;
+               cd->error_status = status;
+       }
+}
+
+FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write)
+{
+       FLAC__StreamDecoder *decoder;
+       ClientData client_data;
+       FLAC__bool ok = true;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+       client_data.seektable_template = &block->data.seek_table;
+       client_data.samples_written = 0;
+       /* client_data.audio_offset must be determined later */
+       client_data.first_seekpoint_to_check = 0;
+       client_data.error_occurred = false;
+
+       decoder = FLAC__stream_decoder_new();
+
+       if(0 == decoder) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) creating the decoder instance\n", filename);
+               return false;
+       }
+
+       FLAC__stream_decoder_set_md5_checking(decoder, false);
+       FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+
+       if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, /*metadata_callback=*/0, error_callback_, &client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) initializing the decoder instance (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+               ok = false;
+       }
+
+       if(ok && !FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+               ok = false;
+       }
+
+       if(ok && !FLAC__stream_decoder_get_decode_position(decoder, &client_data.audio_offset)) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file\n", filename);
+               ok = false;
+       }
+       client_data.last_offset = client_data.audio_offset;
+
+       if(ok && !FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder));
+               ok = false;
+       }
+
+       if(ok && client_data.error_occurred) {
+               fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%u:%s)\n", filename, (unsigned)client_data.error_status, FLAC__StreamDecoderErrorStatusString[client_data.error_status]);
+               ok = false;
+       }
+
+       *needs_write = true;
+       FLAC__stream_decoder_delete(decoder);
+       return ok;
+}
diff --git a/src/metaflac/operations_shorthand_streaminfo.c b/src/metaflac/operations_shorthand_streaminfo.c
new file mode 100644 (file)
index 0000000..b4593f5
--- /dev/null
@@ -0,0 +1,129 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include <string.h>
+#include "operations_shorthand.h"
+
+FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
+{
+       unsigned i;
+       FLAC__bool ok = true;
+       FLAC__StreamMetadata *block;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       block = FLAC__metadata_iterator_get_block(iterator);
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+       if(prefix_with_filename)
+               printf("%s:", filename);
+
+       switch(operation->type) {
+               case OP__SHOW_MD5SUM:
+                       for(i = 0; i < 16; i++)
+                               printf("%02x", block->data.stream_info.md5sum[i]);
+                       printf("\n");
+                       break;
+               case OP__SHOW_MIN_BLOCKSIZE:
+                       printf("%u\n", block->data.stream_info.min_blocksize);
+                       break;
+               case OP__SHOW_MAX_BLOCKSIZE:
+                       printf("%u\n", block->data.stream_info.max_blocksize);
+                       break;
+               case OP__SHOW_MIN_FRAMESIZE:
+                       printf("%u\n", block->data.stream_info.min_framesize);
+                       break;
+               case OP__SHOW_MAX_FRAMESIZE:
+                       printf("%u\n", block->data.stream_info.max_framesize);
+                       break;
+               case OP__SHOW_SAMPLE_RATE:
+                       printf("%u\n", block->data.stream_info.sample_rate);
+                       break;
+               case OP__SHOW_CHANNELS:
+                       printf("%u\n", block->data.stream_info.channels);
+                       break;
+               case OP__SHOW_BPS:
+                       printf("%u\n", block->data.stream_info.bits_per_sample);
+                       break;
+               case OP__SHOW_TOTAL_SAMPLES:
+#ifdef _MSC_VER
+                       printf("%I64u\n", block->data.stream_info.total_samples);
+#else
+                       printf("%llu\n", (unsigned long long)block->data.stream_info.total_samples);
+#endif
+                       break;
+               case OP__SET_MD5SUM:
+                       memcpy(block->data.stream_info.md5sum, operation->argument.streaminfo_md5.value, 16);
+                       *needs_write = true;
+                       break;
+               case OP__SET_MIN_BLOCKSIZE:
+                       block->data.stream_info.min_blocksize = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_MAX_BLOCKSIZE:
+                       block->data.stream_info.max_blocksize = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_MIN_FRAMESIZE:
+                       block->data.stream_info.min_framesize = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_MAX_FRAMESIZE:
+                       block->data.stream_info.max_framesize = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_SAMPLE_RATE:
+                       block->data.stream_info.sample_rate = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_CHANNELS:
+                       block->data.stream_info.channels = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_BPS:
+                       block->data.stream_info.bits_per_sample = operation->argument.streaminfo_uint32.value;
+                       *needs_write = true;
+                       break;
+               case OP__SET_TOTAL_SAMPLES:
+                       block->data.stream_info.total_samples = operation->argument.streaminfo_uint64.value;
+                       *needs_write = true;
+                       break;
+               default:
+                       ok = false;
+                       FLAC__ASSERT(0);
+                       break;
+       };
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       return ok;
+}
diff --git a/src/metaflac/operations_shorthand_vorbiscomment.c b/src/metaflac/operations_shorthand_vorbiscomment.c
new file mode 100644 (file)
index 0000000..ba00859
--- /dev/null
@@ -0,0 +1,368 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h" /* for grabbag__file_get_filesize() */
+#include "share/utf8.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "operations_shorthand.h"
+
+static FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
+static FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write);
+static FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write);
+static FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw);
+static FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw);
+static FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw);
+
+FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw)
+{
+       FLAC__bool ok = true, found_vc_block = false;
+       FLAC__StreamMetadata *block = 0;
+       FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+
+       if(0 == iterator)
+               die("out of memory allocating iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       do {
+               block = FLAC__metadata_iterator_get_block(iterator);
+               if(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+                       found_vc_block = true;
+       } while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+       if(!found_vc_block) {
+               /* create a new block if necessary */
+               if(operation->type == OP__SET_VC_FIELD || operation->type == OP__IMPORT_VC_FROM) {
+                       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+                       if(0 == block)
+                               die("out of memory allocating VORBIS_COMMENT block");
+                       while(FLAC__metadata_iterator_next(iterator))
+                               ;
+                       if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) {
+                               print_error_with_chain_status(chain, "%s: ERROR: adding new VORBIS_COMMENT block to metadata", filename);
+                               return false;
+                       }
+                       /* iterator is left pointing to new block */
+                       FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block);
+               }
+               else {
+                       FLAC__metadata_iterator_delete(iterator);
+                       return ok;
+               }
+       }
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       switch(operation->type) {
+               case OP__SHOW_VC_VENDOR:
+                       write_vc_field(prefix_with_filename? filename : 0, &block->data.vorbis_comment.vendor_string, raw, stdout);
+                       break;
+               case OP__SHOW_VC_FIELD:
+                       write_vc_fields(prefix_with_filename? filename : 0, operation->argument.vc_field_name.value, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, stdout);
+                       break;
+               case OP__REMOVE_VC_ALL:
+                       ok = remove_vc_all(filename, block, needs_write);
+                       break;
+               case OP__REMOVE_VC_FIELD:
+                       ok = remove_vc_field(filename, block, operation->argument.vc_field_name.value, needs_write);
+                       break;
+               case OP__REMOVE_VC_FIRSTFIELD:
+                       ok = remove_vc_firstfield(filename, block, operation->argument.vc_field_name.value, needs_write);
+                       break;
+               case OP__SET_VC_FIELD:
+                       ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, raw);
+                       break;
+               case OP__IMPORT_VC_FROM:
+                       ok = import_vc_from(filename, block, &operation->argument.filename, needs_write, raw);
+                       break;
+               case OP__EXPORT_VC_TO:
+                       ok = export_vc_to(filename, block, &operation->argument.filename, raw);
+                       break;
+               default:
+                       ok = false;
+                       FLAC__ASSERT(0);
+                       break;
+       };
+
+       FLAC__metadata_iterator_delete(iterator);
+       return ok;
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write)
+{
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != needs_write);
+
+       if(0 != block->data.vorbis_comment.comments) {
+               FLAC__ASSERT(block->data.vorbis_comment.num_comments > 0);
+               if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, 0)) {
+                       fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+                       return false;
+               }
+               *needs_write = true;
+       }
+       else {
+               FLAC__ASSERT(block->data.vorbis_comment.num_comments == 0);
+       }
+
+       return true;
+}
+
+FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write)
+{
+       int n;
+
+       FLAC__ASSERT(0 != needs_write);
+
+       n = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, field_name);
+
+       if(n < 0) {
+               fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+               return false;
+       }
+       else if(n > 0)
+               *needs_write = true;
+
+       return true;
+}
+
+FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write)
+{
+       int n;
+
+       FLAC__ASSERT(0 != needs_write);
+
+       n = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, field_name);
+
+       if(n < 0) {
+               fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+               return false;
+       }
+       else if(n > 0)
+               *needs_write = true;
+
+       return true;
+}
+
+FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw)
+{
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+       char *converted;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != field);
+       FLAC__ASSERT(0 != needs_write);
+
+       if(field->field_value_from_file) {
+               /* read the file into 'data' */
+               FILE *f = 0;
+               char *data = 0;
+               const off_t size = grabbag__file_get_filesize(field->field_value);
+               if(size < 0) {
+                       fprintf(stderr, "%s: ERROR: can't open file '%s' for '%s' tag value\n", filename, field->field_value, field->field_name);
+                       return false;
+               }
+               if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */
+                       fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is too large\n", filename, field->field_value, field->field_name);
+                       return false;
+               }
+               if(0 == (data = malloc(size+1)))
+                       die("out of memory allocating tag value");
+               data[size] = '\0';
+               if(0 == (f = fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) {
+                       fprintf(stderr, "%s: ERROR: while reading file '%s' for '%s' tag value: %s\n", filename, field->field_value, field->field_name, strerror(errno));
+                       free(data);
+                       if(f)
+                               fclose(f);
+                       return false;
+               }
+               fclose(f);
+               if(strlen(data) != (size_t)size) {
+                       free(data);
+                       fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value has embedded NULs\n", filename, field->field_value, field->field_name);
+                       return false;
+               }
+
+               /* move 'data' into 'converted', converting to UTF-8 if necessary */
+               if(raw) {
+                       converted = data;
+               }
+               else if(utf8_encode(data, &converted) >= 0) {
+                       free(data);
+               }
+               else {
+                       free(data);
+                       fprintf(stderr, "%s: ERROR: converting file '%s' contents to UTF-8 for tag value\n", filename, field->field_value);
+                       return false;
+               }
+
+               /* create and entry and append it */
+               if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) {
+                       free(converted);
+                       fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is not valid UTF-8\n", filename, field->field_value, field->field_name);
+                       return false;
+               }
+               free(converted);
+               if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+                       fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+                       return false;
+               }
+
+               *needs_write = true;
+               return true;
+       }
+       else {
+               FLAC__bool needs_free = false;
+               if(raw) {
+                       entry.entry = (FLAC__byte *)field->field;
+               }
+               else if(utf8_encode(field->field, &converted) >= 0) {
+                       entry.entry = (FLAC__byte *)converted;
+                       needs_free = true;
+               }
+               else {
+                       fprintf(stderr, "%s: ERROR: converting comment '%s' to UTF-8\n", filename, field->field);
+                       return false;
+               }
+               entry.length = strlen((const char *)entry.entry);
+               if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) {
+                       if(needs_free)
+                               free(converted);
+                       /*
+                        * our previous parsing has already established that the field
+                        * name is OK, so it must be the field value
+                        */
+                       fprintf(stderr, "%s: ERROR: tag value for '%s' is not valid UTF-8\n", filename, field->field_name);
+                       return false;
+               }
+
+               if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+                       if(needs_free)
+                               free(converted);
+                       fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+                       return false;
+               }
+
+               *needs_write = true;
+               if(needs_free)
+                       free(converted);
+               return true;
+       }
+}
+
+FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw)
+{
+       FILE *f;
+       char line[65536];
+       FLAC__bool ret;
+
+       if(0 == vc_filename->value || strlen(vc_filename->value) == 0) {
+               fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+               return false;
+       }
+       if(0 == strcmp(vc_filename->value, "-"))
+               f = stdin;
+       else
+               f = fopen(vc_filename->value, "r");
+
+       if(0 == f) {
+               fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, vc_filename->value, strerror(errno));
+               return false;
+       }
+
+       ret = true;
+       while(ret && !feof(f)) {
+               fgets(line, sizeof(line), f);
+               if(!feof(f)) {
+                       char *p = strchr(line, '\n');
+                       if(0 == p) {
+                               fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value);
+                               ret = false;
+                       }
+                       else {
+                               const char *violation;
+                               Argument_VcField field;
+                               *p = '\0';
+                               memset(&field, 0, sizeof(Argument_VcField));
+                               field.field_value_from_file = false;
+                               if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) {
+                                       FLAC__ASSERT(0 != violation);
+                                       fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n       %s\n", vc_filename->value, line, violation);
+                                       ret = false;
+                               }
+                               else {
+                                       ret = set_vc_field(filename, block, &field, needs_write, raw);
+                               }
+                               if(0 != field.field)
+                                       free(field.field);
+                               if(0 != field.field_name)
+                                       free(field.field_name);
+                               if(0 != field.field_value)
+                                       free(field.field_value);
+                       }
+               }
+       };
+
+       if(f != stdin)
+               fclose(f);
+       return ret;
+}
+
+FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw)
+{
+       FILE *f;
+       FLAC__bool ret;
+
+       if(0 == vc_filename->value || strlen(vc_filename->value) == 0) {
+               fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+               return false;
+       }
+       if(0 == strcmp(vc_filename->value, "-"))
+               f = stdout;
+       else
+               f = fopen(vc_filename->value, "w");
+
+       if(0 == f) {
+               fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, vc_filename->value, strerror(errno));
+               return false;
+       }
+
+       ret = true;
+
+       write_vc_fields(0, 0, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, f);
+
+       if(f != stdout)
+               fclose(f);
+       return ret;
+}
diff --git a/src/metaflac/options.c b/src/metaflac/options.c
new file mode 100644 (file)
index 0000000..56c4416
--- /dev/null
@@ -0,0 +1,1109 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "options.h"
+#include "usage.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/grabbag/replaygain.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+   share__getopt format struct; note we don't use short options so we just
+   set the 'val' field to 0 everywhere to indicate a valid option.
+*/
+struct share__option long_options_[] = {
+       /* global options */
+       { "preserve-modtime", 0, 0, 0 },
+       { "with-filename", 0, 0, 0 },
+       { "no-filename", 0, 0, 0 },
+       { "no-utf8-convert", 0, 0, 0 },
+       { "dont-use-padding", 0, 0, 0 },
+       { "no-cued-seekpoints", 0, 0, 0 },
+       /* shorthand operations */
+       { "show-md5sum", 0, 0, 0 },
+       { "show-min-blocksize", 0, 0, 0 },
+       { "show-max-blocksize", 0, 0, 0 },
+       { "show-min-framesize", 0, 0, 0 },
+       { "show-max-framesize", 0, 0, 0 },
+       { "show-sample-rate", 0, 0, 0 },
+       { "show-channels", 0, 0, 0 },
+       { "show-bps", 0, 0, 0 },
+       { "show-total-samples", 0, 0, 0 },
+       { "set-md5sum", 1, 0, 0 }, /* undocumented */
+       { "set-min-blocksize", 1, 0, 0 }, /* undocumented */
+       { "set-max-blocksize", 1, 0, 0 }, /* undocumented */
+       { "set-min-framesize", 1, 0, 0 }, /* undocumented */
+       { "set-max-framesize", 1, 0, 0 }, /* undocumented */
+       { "set-sample-rate", 1, 0, 0 }, /* undocumented */
+       { "set-channels", 1, 0, 0 }, /* undocumented */
+       { "set-bps", 1, 0, 0 }, /* undocumented */
+       { "set-total-samples", 1, 0, 0 }, /* undocumented */ /* WATCHOUT: used by test/test_flac.sh on windows */
+       { "show-vendor-tag", 0, 0, 0 }, 
+       { "show-tag", 1, 0, 0 }, 
+       { "remove-all-tags", 0, 0, 0 }, 
+       { "remove-tag", 1, 0, 0 }, 
+       { "remove-first-tag", 1, 0, 0 }, 
+       { "set-tag", 1, 0, 0 }, 
+       { "set-tag-from-file", 1, 0, 0 }, 
+       { "import-tags-from", 1, 0, 0 }, 
+       { "export-tags-to", 1, 0, 0 }, 
+       { "import-cuesheet-from", 1, 0, 0 },
+       { "export-cuesheet-to", 1, 0, 0 },
+       { "import-picture-from", 1, 0, 0 },
+       { "export-picture-to", 1, 0, 0 },
+       { "add-seekpoint", 1, 0, 0 },
+       { "add-replay-gain", 0, 0, 0 },
+       { "remove-replay-gain", 0, 0, 0 },
+       { "add-padding", 1, 0, 0 },
+       /* major operations */
+       { "help", 0, 0, 0 },
+       { "version", 0, 0, 0 },
+       { "list", 0, 0, 0 },
+       { "append", 0, 0, 0 },
+       { "remove", 0, 0, 0 },
+       { "remove-all", 0, 0, 0 },
+       { "merge-padding", 0, 0, 0 },
+       { "sort-padding", 0, 0, 0 },
+       /* major operation arguments */
+       { "block-number", 1, 0, 0 },
+       { "block-type", 1, 0, 0 },
+       { "except-block-type", 1, 0, 0 },
+       { "data-format", 1, 0, 0 },
+       { "application-data-format", 1, 0, 0 },
+       { "from-file", 1, 0, 0 },
+       {0, 0, 0, 0}
+};
+
+static FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options);
+static void append_new_operation(CommandLineOptions *options, Operation operation);
+static void append_new_argument(CommandLineOptions *options, Argument argument);
+static Operation *append_major_operation(CommandLineOptions *options, OperationType type);
+static Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type);
+static Argument *find_argument(CommandLineOptions *options, ArgumentType type);
+static Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type);
+static Argument *append_argument(CommandLineOptions *options, ArgumentType type);
+static FLAC__bool parse_md5(const char *src, FLAC__byte dest[16]);
+static FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest);
+static FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest);
+static FLAC__bool parse_string(const char *src, char **dest);
+static FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation);
+static FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation);
+static FLAC__bool parse_add_padding(const char *in, unsigned *out);
+static FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out);
+static FLAC__bool parse_block_type(const char *in, Argument_BlockType *out);
+static FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out);
+static FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out);
+static void undocumented_warning(const char *opt);
+
+
+void init_options(CommandLineOptions *options)
+{
+       options->preserve_modtime = false;
+
+       /* '2' is a hack to mean "use default if not forced on command line" */
+       FLAC__ASSERT(true != 2);
+       options->prefix_with_filename = 2;
+
+       options->utf8_convert = true;
+       options->use_padding = true;
+       options->cued_seekpoints = true;
+       options->show_long_help = false;
+       options->show_version = false;
+       options->application_data_format_is_hexdump = false;
+
+       options->ops.operations = 0;
+       options->ops.num_operations = 0;
+       options->ops.capacity = 0;
+
+       options->args.arguments = 0;
+       options->args.num_arguments = 0;
+       options->args.capacity = 0;
+
+       options->args.checks.num_shorthand_ops = 0;
+       options->args.checks.num_major_ops = 0;
+       options->args.checks.has_block_type = false;
+       options->args.checks.has_except_block_type = false;
+
+       options->num_files = 0;
+       options->filenames = 0;
+}
+
+FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options)
+{
+       int ret;
+       int option_index = 1;
+       FLAC__bool had_error = false;
+
+       while ((ret = share__getopt_long(argc, argv, "", long_options_, &option_index)) != -1) {
+               switch (ret) {
+                       case 0:
+                               had_error |= !parse_option(option_index, share__optarg, options);
+                               break;
+                       case '?':
+                       case ':':
+                               had_error = true;
+                               break;
+                       default:
+                               FLAC__ASSERT(0);
+                               break;
+               }
+       }
+
+       if(options->prefix_with_filename == 2)
+               options->prefix_with_filename = (argc - share__optind > 1);
+
+       if(share__optind >= argc && !options->show_long_help && !options->show_version) {
+               fprintf(stderr,"ERROR: you must specify at least one FLAC file;\n");
+               fprintf(stderr,"       metaflac cannot be used as a pipe\n");
+               had_error = true;
+       }
+
+       options->num_files = argc - share__optind;
+
+       if(options->num_files > 0) {
+               unsigned i = 0;
+               if(0 == (options->filenames = (char**)safe_malloc_mul_2op_(sizeof(char*), /*times*/options->num_files)))
+                       die("out of memory allocating space for file names list");
+               while(share__optind < argc)
+                       options->filenames[i++] = local_strdup(argv[share__optind++]);
+       }
+
+       if(options->args.checks.num_major_ops > 0) {
+               if(options->args.checks.num_major_ops > 1) {
+                       fprintf(stderr, "ERROR: you may only specify one major operation at a time\n");
+                       had_error = true;
+               }
+               else if(options->args.checks.num_shorthand_ops > 0) {
+                       fprintf(stderr, "ERROR: you may not mix shorthand and major operations\n");
+                       had_error = true;
+               }
+       }
+
+       /* check for only one FLAC file used with certain options */
+       if(options->num_files > 1) {
+               if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
+                       fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-cuesheet-from'\n");
+                       had_error = true;
+               }
+               if(0 != find_shorthand_operation(options, OP__EXPORT_CUESHEET_TO)) {
+                       fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-cuesheet-to'\n");
+                       had_error = true;
+               }
+               if(0 != find_shorthand_operation(options, OP__EXPORT_PICTURE_TO)) {
+                       fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-picture-to'\n");
+                       had_error = true;
+               }
+               if(
+                       0 != find_shorthand_operation(options, OP__IMPORT_VC_FROM) &&
+                       0 == strcmp(find_shorthand_operation(options, OP__IMPORT_VC_FROM)->argument.filename.value, "-")
+               ) {
+                       fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-tags-from=-'\n");
+                       had_error = true;
+               }
+       }
+
+       if(options->args.checks.has_block_type && options->args.checks.has_except_block_type) {
+               fprintf(stderr, "ERROR: you may not specify both '--block-type' and '--except-block-type'\n");
+               had_error = true;
+       }
+
+       if(had_error)
+               short_usage(0);
+
+       /*
+        * We need to create an OP__ADD_SEEKPOINT operation if there is
+        * not one already, and --import-cuesheet-from was specified but
+        * --no-cued-seekpoints was not:
+        */
+       if(options->cued_seekpoints) {
+               Operation *op = find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
+               if(0 != op) {
+                       Operation *op2 = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
+                       if(0 == op2)
+                               op2 = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
+                       op->argument.import_cuesheet_from.add_seekpoint_link = &(op2->argument.add_seekpoint);
+               }
+       }
+
+       return !had_error;
+}
+
+void free_options(CommandLineOptions *options)
+{
+       unsigned i;
+       Operation *op;
+       Argument *arg;
+
+       FLAC__ASSERT(0 == options->ops.operations || options->ops.num_operations > 0);
+       FLAC__ASSERT(0 == options->args.arguments || options->args.num_arguments > 0);
+
+       for(i = 0, op = options->ops.operations; i < options->ops.num_operations; i++, op++) {
+               switch(op->type) {
+                       case OP__SHOW_VC_FIELD:
+                       case OP__REMOVE_VC_FIELD:
+                       case OP__REMOVE_VC_FIRSTFIELD:
+                               if(0 != op->argument.vc_field_name.value)
+                                       free(op->argument.vc_field_name.value);
+                               break;
+                       case OP__SET_VC_FIELD:
+                               if(0 != op->argument.vc_field.field)
+                                       free(op->argument.vc_field.field);
+                               if(0 != op->argument.vc_field.field_name)
+                                       free(op->argument.vc_field.field_name);
+                               if(0 != op->argument.vc_field.field_value)
+                                       free(op->argument.vc_field.field_value);
+                               break;
+                       case OP__IMPORT_VC_FROM:
+                       case OP__EXPORT_VC_TO:
+                       case OP__EXPORT_CUESHEET_TO:
+                               if(0 != op->argument.filename.value)
+                                       free(op->argument.filename.value);
+                               break;
+                       case OP__IMPORT_CUESHEET_FROM:
+                               if(0 != op->argument.import_cuesheet_from.filename)
+                                       free(op->argument.import_cuesheet_from.filename);
+                               break;
+                       case OP__IMPORT_PICTURE_FROM:
+                               if(0 != op->argument.specification.value)
+                                       free(op->argument.specification.value);
+                               break;
+                       case OP__EXPORT_PICTURE_TO:
+                               if(0 != op->argument.export_picture_to.filename)
+                                       free(op->argument.export_picture_to.filename);
+                               break;
+                       case OP__ADD_SEEKPOINT:
+                               if(0 != op->argument.add_seekpoint.specification)
+                                       free(op->argument.add_seekpoint.specification);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       for(i = 0, arg = options->args.arguments; i < options->args.num_arguments; i++, arg++) {
+               switch(arg->type) {
+                       case ARG__BLOCK_NUMBER:
+                               if(0 != arg->value.block_number.entries)
+                                       free(arg->value.block_number.entries);
+                               break;
+                       case ARG__BLOCK_TYPE:
+                       case ARG__EXCEPT_BLOCK_TYPE:
+                               if(0 != arg->value.block_type.entries)
+                                       free(arg->value.block_type.entries);
+                               break;
+                       case ARG__FROM_FILE:
+                               if(0 != arg->value.from_file.file_name)
+                                       free(arg->value.from_file.file_name);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       if(0 != options->ops.operations)
+               free(options->ops.operations);
+
+       if(0 != options->args.arguments)
+               free(options->args.arguments);
+
+       if(0 != options->filenames) {
+               for(i = 0; i < options->num_files; i++) {
+                       if(0 != options->filenames[i])
+                               free(options->filenames[i]);
+               }
+               free(options->filenames);
+       }
+}
+
+/*
+ * local routines
+ */
+
+FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options)
+{
+       const char *opt = long_options_[option_index].name;
+       Operation *op;
+       Argument *arg;
+       FLAC__bool ok = true;
+
+       if(0 == strcmp(opt, "preserve-modtime")) {
+               options->preserve_modtime = true;
+       }
+       else if(0 == strcmp(opt, "with-filename")) {
+               options->prefix_with_filename = true;
+       }
+       else if(0 == strcmp(opt, "no-filename")) {
+               options->prefix_with_filename = false;
+       }
+       else if(0 == strcmp(opt, "no-utf8-convert")) {
+               options->utf8_convert = false;
+       }
+       else if(0 == strcmp(opt, "dont-use-padding")) {
+               options->use_padding = false;
+       }
+       else if(0 == strcmp(opt, "no-cued-seekpoints")) {
+               options->cued_seekpoints = false;
+       }
+       else if(0 == strcmp(opt, "show-md5sum")) {
+               (void) append_shorthand_operation(options, OP__SHOW_MD5SUM);
+       }
+       else if(0 == strcmp(opt, "show-min-blocksize")) {
+               (void) append_shorthand_operation(options, OP__SHOW_MIN_BLOCKSIZE);
+       }
+       else if(0 == strcmp(opt, "show-max-blocksize")) {
+               (void) append_shorthand_operation(options, OP__SHOW_MAX_BLOCKSIZE);
+       }
+       else if(0 == strcmp(opt, "show-min-framesize")) {
+               (void) append_shorthand_operation(options, OP__SHOW_MIN_FRAMESIZE);
+       }
+       else if(0 == strcmp(opt, "show-max-framesize")) {
+               (void) append_shorthand_operation(options, OP__SHOW_MAX_FRAMESIZE);
+       }
+       else if(0 == strcmp(opt, "show-sample-rate")) {
+               (void) append_shorthand_operation(options, OP__SHOW_SAMPLE_RATE);
+       }
+       else if(0 == strcmp(opt, "show-channels")) {
+               (void) append_shorthand_operation(options, OP__SHOW_CHANNELS);
+       }
+       else if(0 == strcmp(opt, "show-bps")) {
+               (void) append_shorthand_operation(options, OP__SHOW_BPS);
+       }
+       else if(0 == strcmp(opt, "show-total-samples")) {
+               (void) append_shorthand_operation(options, OP__SHOW_TOTAL_SAMPLES);
+       }
+       else if(0 == strcmp(opt, "set-md5sum")) {
+               op = append_shorthand_operation(options, OP__SET_MD5SUM);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_md5(option_argument, op->argument.streaminfo_md5.value)) {
+                       fprintf(stderr, "ERROR (--%s): bad MD5 sum\n", opt);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-min-blocksize")) {
+               op = append_shorthand_operation(options, OP__SET_MIN_BLOCKSIZE);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
+                       fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-max-blocksize")) {
+               op = append_shorthand_operation(options, OP__SET_MAX_BLOCKSIZE);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
+                       fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-min-framesize")) {
+               op = append_shorthand_operation(options, OP__SET_MIN_FRAMESIZE);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) {
+                       fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-max-framesize")) {
+               op = append_shorthand_operation(options, OP__SET_MAX_FRAMESIZE);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) {
+                       fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-sample-rate")) {
+               op = append_shorthand_operation(options, OP__SET_SAMPLE_RATE);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || !FLAC__format_sample_rate_is_valid(op->argument.streaminfo_uint32.value)) {
+                       fprintf(stderr, "ERROR (--%s): invalid sample rate\n", opt);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-channels")) {
+               op = append_shorthand_operation(options, OP__SET_CHANNELS);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value > FLAC__MAX_CHANNELS) {
+                       fprintf(stderr, "ERROR (--%s): value must be > 0 and <= %u\n", opt, FLAC__MAX_CHANNELS);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-bps")) {
+               op = append_shorthand_operation(options, OP__SET_BPS);
+               if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BITS_PER_SAMPLE || op->argument.streaminfo_uint32.value > FLAC__MAX_BITS_PER_SAMPLE) {
+                       fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "set-total-samples")) {
+               op = append_shorthand_operation(options, OP__SET_TOTAL_SAMPLES);
+               if(!parse_uint64(option_argument, &(op->argument.streaminfo_uint64.value)) || op->argument.streaminfo_uint64.value >= (((FLAC__uint64)1)<<FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) {
+                       fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
+                       ok = false;
+               }
+               else
+                       undocumented_warning(opt);
+       }
+       else if(0 == strcmp(opt, "show-vendor-tag")) {
+               (void) append_shorthand_operation(options, OP__SHOW_VC_VENDOR);
+       }
+       else if(0 == strcmp(opt, "show-tag")) {
+               const char *violation;
+               op = append_shorthand_operation(options, OP__SHOW_VC_FIELD);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "remove-all-tags")) {
+               (void) append_shorthand_operation(options, OP__REMOVE_VC_ALL);
+       }
+       else if(0 == strcmp(opt, "remove-tag")) {
+               const char *violation;
+               op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "remove-first-tag")) {
+               const char *violation;
+               op = append_shorthand_operation(options, OP__REMOVE_VC_FIRSTFIELD);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "set-tag")) {
+               const char *violation;
+               op = append_shorthand_operation(options, OP__SET_VC_FIELD);
+               FLAC__ASSERT(0 != option_argument);
+               op->argument.vc_field.field_value_from_file = false;
+               if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "set-tag-from-file")) {
+               const char *violation;
+               op = append_shorthand_operation(options, OP__SET_VC_FIELD);
+               FLAC__ASSERT(0 != option_argument);
+               op->argument.vc_field.field_value_from_file = true;
+               if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "import-tags-from")) {
+               op = append_shorthand_operation(options, OP__IMPORT_VC_FROM);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.filename.value))) {
+                       fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "export-tags-to")) {
+               op = append_shorthand_operation(options, OP__EXPORT_VC_TO);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.filename.value))) {
+                       fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "import-cuesheet-from")) {
+               if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
+                       fprintf(stderr, "ERROR (--%s): may be specified only once\n", opt);
+                       ok = false;
+               }
+               op = append_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.import_cuesheet_from.filename))) {
+                       fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "export-cuesheet-to")) {
+               op = append_shorthand_operation(options, OP__EXPORT_CUESHEET_TO);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.filename.value))) {
+                       fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "import-picture-from")) {
+               op = append_shorthand_operation(options, OP__IMPORT_PICTURE_FROM);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.specification.value))) {
+                       fprintf(stderr, "ERROR (--%s): missing specification\n", opt);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "export-picture-to")) {
+               const Argument *arg = find_argument(options, ARG__BLOCK_NUMBER);
+               op = append_shorthand_operation(options, OP__EXPORT_PICTURE_TO);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_string(option_argument, &(op->argument.export_picture_to.filename))) {
+                       fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
+                       ok = false;
+               }
+               op->argument.export_picture_to.block_number_link = arg? &(arg->value.block_number) : 0;
+       }
+       else if(0 == strcmp(opt, "add-seekpoint")) {
+               const char *violation;
+               char *spec;
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_add_seekpoint(option_argument, &spec, &violation)) {
+                       FLAC__ASSERT(0 != violation);
+                       fprintf(stderr, "ERROR (--%s): malformed seekpoint specification \"%s\",\n       %s\n", opt, option_argument, violation);
+                       ok = false;
+               }
+               else {
+                       op = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
+                       if(0 == op)
+                               op = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
+                       local_strcat(&(op->argument.add_seekpoint.specification), spec);
+                       local_strcat(&(op->argument.add_seekpoint.specification), ";");
+                       free(spec);
+               }
+       }
+       else if(0 == strcmp(opt, "add-replay-gain")) {
+               (void) append_shorthand_operation(options, OP__ADD_REPLAY_GAIN);
+       }
+       else if(0 == strcmp(opt, "remove-replay-gain")) {
+               const FLAC__byte * const tags[5] = {
+                       GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS,
+                       GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN,
+                       GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK,
+                       GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN,
+                       GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK
+               };
+               size_t i;
+               for(i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) {
+                       op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
+                       op->argument.vc_field_name.value = local_strdup((const char *)tags[i]);
+               }
+       }
+       else if(0 == strcmp(opt, "add-padding")) {
+               op = append_shorthand_operation(options, OP__ADD_PADDING);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_add_padding(option_argument, &(op->argument.add_padding.length))) {
+                       fprintf(stderr, "ERROR (--%s): illegal length \"%s\", length must be >= 0 and < 2^%u\n", opt, option_argument, FLAC__STREAM_METADATA_LENGTH_LEN);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "help")) {
+               options->show_long_help = true;
+       }
+       else if(0 == strcmp(opt, "version")) {
+               options->show_version = true;
+       }
+       else if(0 == strcmp(opt, "list")) {
+               (void) append_major_operation(options, OP__LIST);
+       }
+       else if(0 == strcmp(opt, "append")) {
+               (void) append_major_operation(options, OP__APPEND);
+       }
+       else if(0 == strcmp(opt, "remove")) {
+               (void) append_major_operation(options, OP__REMOVE);
+       }
+       else if(0 == strcmp(opt, "remove-all")) {
+               (void) append_major_operation(options, OP__REMOVE_ALL);
+       }
+       else if(0 == strcmp(opt, "merge-padding")) {
+               (void) append_major_operation(options, OP__MERGE_PADDING);
+       }
+       else if(0 == strcmp(opt, "sort-padding")) {
+               (void) append_major_operation(options, OP__SORT_PADDING);
+       }
+       else if(0 == strcmp(opt, "block-number")) {
+               arg = append_argument(options, ARG__BLOCK_NUMBER);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_block_number(option_argument, &(arg->value.block_number))) {
+                       fprintf(stderr, "ERROR: malformed block number specification \"%s\"\n", option_argument);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "block-type")) {
+               arg = append_argument(options, ARG__BLOCK_TYPE);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_block_type(option_argument, &(arg->value.block_type))) {
+                       fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
+                       ok = false;
+               }
+               options->args.checks.has_block_type = true;
+       }
+       else if(0 == strcmp(opt, "except-block-type")) {
+               arg = append_argument(options, ARG__EXCEPT_BLOCK_TYPE);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_block_type(option_argument, &(arg->value.block_type))) {
+                       fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
+                       ok = false;
+               }
+               options->args.checks.has_except_block_type = true;
+       }
+       else if(0 == strcmp(opt, "data-format")) {
+               arg = append_argument(options, ARG__DATA_FORMAT);
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_data_format(option_argument, &(arg->value.data_format))) {
+                       fprintf(stderr, "ERROR (--%s): illegal data format \"%s\"\n", opt, option_argument);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "application-data-format")) {
+               FLAC__ASSERT(0 != option_argument);
+               if(!parse_application_data_format(option_argument, &(options->application_data_format_is_hexdump))) {
+                       fprintf(stderr, "ERROR (--%s): illegal application data format \"%s\"\n", opt, option_argument);
+                       ok = false;
+               }
+       }
+       else if(0 == strcmp(opt, "from-file")) {
+               arg = append_argument(options, ARG__FROM_FILE);
+               FLAC__ASSERT(0 != option_argument);
+               arg->value.from_file.file_name = local_strdup(option_argument);
+       }
+       else {
+               FLAC__ASSERT(0);
+       }
+
+       return ok;
+}
+
+void append_new_operation(CommandLineOptions *options, Operation operation)
+{
+       if(options->ops.capacity == 0) {
+               options->ops.capacity = 50;
+               if(0 == (options->ops.operations = (Operation*)malloc(sizeof(Operation) * options->ops.capacity)))
+                       die("out of memory allocating space for option list");
+               memset(options->ops.operations, 0, sizeof(Operation) * options->ops.capacity);
+       }
+       if(options->ops.capacity <= options->ops.num_operations) {
+               unsigned original_capacity = options->ops.capacity;
+               if(options->ops.capacity > SIZE_MAX / 2) /* overflow check */
+                       die("out of memory allocating space for option list");
+               options->ops.capacity *= 2;
+               if(0 == (options->ops.operations = (Operation*)safe_realloc_mul_2op_(options->ops.operations, sizeof(Operation), /*times*/options->ops.capacity)))
+                       die("out of memory allocating space for option list");
+               memset(options->ops.operations + original_capacity, 0, sizeof(Operation) * (options->ops.capacity - original_capacity));
+       }
+
+       options->ops.operations[options->ops.num_operations++] = operation;
+}
+
+void append_new_argument(CommandLineOptions *options, Argument argument)
+{
+       if(options->args.capacity == 0) {
+               options->args.capacity = 50;
+               if(0 == (options->args.arguments = (Argument*)malloc(sizeof(Argument) * options->args.capacity)))
+                       die("out of memory allocating space for option list");
+               memset(options->args.arguments, 0, sizeof(Argument) * options->args.capacity);
+       }
+       if(options->args.capacity <= options->args.num_arguments) {
+               unsigned original_capacity = options->args.capacity;
+               if(options->args.capacity > SIZE_MAX / 2) /* overflow check */
+                       die("out of memory allocating space for option list");
+               options->args.capacity *= 2;
+               if(0 == (options->args.arguments = (Argument*)safe_realloc_mul_2op_(options->args.arguments, sizeof(Argument), /*times*/options->args.capacity)))
+                       die("out of memory allocating space for option list");
+               memset(options->args.arguments + original_capacity, 0, sizeof(Argument) * (options->args.capacity - original_capacity));
+       }
+
+       options->args.arguments[options->args.num_arguments++] = argument;
+}
+
+Operation *append_major_operation(CommandLineOptions *options, OperationType type)
+{
+       Operation op;
+       memset(&op, 0, sizeof(op));
+       op.type = type;
+       append_new_operation(options, op);
+       options->args.checks.num_major_ops++;
+       return options->ops.operations + (options->ops.num_operations - 1);
+}
+
+Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type)
+{
+       Operation op;
+       memset(&op, 0, sizeof(op));
+       op.type = type;
+       append_new_operation(options, op);
+       options->args.checks.num_shorthand_ops++;
+       return options->ops.operations + (options->ops.num_operations - 1);
+}
+
+Argument *find_argument(CommandLineOptions *options, ArgumentType type)
+{
+       unsigned i;
+       for(i = 0; i < options->args.num_arguments; i++)
+               if(options->args.arguments[i].type == type)
+                       return &options->args.arguments[i];
+       return 0;
+}
+
+Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type)
+{
+       unsigned i;
+       for(i = 0; i < options->ops.num_operations; i++)
+               if(options->ops.operations[i].type == type)
+                       return &options->ops.operations[i];
+       return 0;
+}
+
+Argument *append_argument(CommandLineOptions *options, ArgumentType type)
+{
+       Argument arg;
+       memset(&arg, 0, sizeof(arg));
+       arg.type = type;
+       append_new_argument(options, arg);
+       return options->args.arguments + (options->args.num_arguments - 1);
+}
+
+FLAC__bool parse_md5(const char *src, FLAC__byte dest[16])
+{
+       unsigned i, d;
+       int c;
+       FLAC__ASSERT(0 != src);
+       if(strlen(src) != 32)
+               return false;
+       /* strtoul() accepts negative numbers which we do not want, so we do it the hard way */
+       for(i = 0; i < 16; i++) {
+               c = (int)(*src++);
+               if(isdigit(c))
+                       d = (unsigned)(c - '0');
+               else if(c >= 'a' && c <= 'f')
+                       d = (unsigned)(c - 'a') + 10u;
+               else if(c >= 'A' && c <= 'F')
+                       d = (unsigned)(c - 'A') + 10u;
+               else
+                       return false;
+               d <<= 4;
+               c = (int)(*src++);
+               if(isdigit(c))
+                       d |= (unsigned)(c - '0');
+               else if(c >= 'a' && c <= 'f')
+                       d |= (unsigned)(c - 'a') + 10u;
+               else if(c >= 'A' && c <= 'F')
+                       d |= (unsigned)(c - 'A') + 10u;
+               else
+                       return false;
+               dest[i] = (FLAC__byte)d;
+       }
+       return true;
+}
+
+FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest)
+{
+       FLAC__ASSERT(0 != src);
+       if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src))
+               return false;
+       *dest = strtoul(src, 0, 10);
+       return true;
+}
+
+#ifdef _MSC_VER
+/* There's no strtoull() in MSVC6 so we just write a specialized one */
+static FLAC__uint64 local__strtoull(const char *src)
+{
+       FLAC__uint64 ret = 0;
+       int c;
+       FLAC__ASSERT(0 != src);
+       while(0 != (c = *src++)) {
+               c -= '0';
+               if(c >= 0 && c <= 9)
+                       ret = (ret * 10) + c;
+               else
+                       break;
+       }
+       return ret;
+}
+#endif
+
+FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest)
+{
+       FLAC__ASSERT(0 != src);
+       if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src))
+               return false;
+#ifdef _MSC_VER
+       *dest = local__strtoull(src);
+#else
+       *dest = strtoull(src, 0, 10);
+#endif
+       return true;
+}
+
+FLAC__bool parse_string(const char *src, char **dest)
+{
+       if(0 == src || strlen(src) == 0)
+               return false;
+       *dest = strdup(src);
+       return true;
+}
+
+FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation)
+{
+       static const char * const violations[] = {
+               "field name contains invalid character"
+       };
+
+       char *q, *s;
+
+       s = local_strdup(field_ref);
+
+       for(q = s; *q; q++) {
+               if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+                       free(s);
+                       *violation = violations[0];
+                       return false;
+               }
+       }
+
+       *name = s;
+
+       return true;
+}
+
+FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation)
+{
+       static const char *garbled_ = "garbled specification";
+       const unsigned n = strlen(in);
+
+       FLAC__ASSERT(0 != in);
+       FLAC__ASSERT(0 != out);
+
+       if(n == 0) {
+               *violation = "specification is empty";
+               return false;
+       }
+
+       if(n > strspn(in, "0123456789.Xsx")) {
+               *violation = "specification contains invalid character";
+               return false;
+       }
+
+       if(in[n-1] == 'X') {
+               if(n > 1) {
+                       *violation = garbled_;
+                       return false;
+               }
+       }
+       else if(in[n-1] == 's') {
+               if(n-1 > strspn(in, "0123456789.")) {
+                       *violation = garbled_;
+                       return false;
+               }
+       }
+       else if(in[n-1] == 'x') {
+               if(n-1 > strspn(in, "0123456789")) {
+                       *violation = garbled_;
+                       return false;
+               }
+       }
+       else {
+               if(n > strspn(in, "0123456789")) {
+                       *violation = garbled_;
+                       return false;
+               }
+       }
+
+       *out = local_strdup(in);
+       return true;
+}
+
+FLAC__bool parse_add_padding(const char *in, unsigned *out)
+{
+       FLAC__ASSERT(0 != in);
+       FLAC__ASSERT(0 != out);
+       *out = (unsigned)strtoul(in, 0, 10);
+       return *out < (1u << FLAC__STREAM_METADATA_LENGTH_LEN);
+}
+
+FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out)
+{
+       char *p, *q, *s, *end;
+       long i;
+       unsigned entry;
+
+       if(*in == '\0')
+               return false;
+
+       s = local_strdup(in);
+
+       /* first count the entries */
+       for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ','))
+               ;
+
+       /* make space */
+       FLAC__ASSERT(out->num_entries > 0);
+       if(0 == (out->entries = (unsigned*)safe_malloc_mul_2op_(sizeof(unsigned), /*times*/out->num_entries)))
+               die("out of memory allocating space for option list");
+
+       /* load 'em up */
+       entry = 0;
+       q = s;
+       while(q) {
+               FLAC__ASSERT(entry < out->num_entries);
+               if(0 != (p = strchr(q, ',')))
+                       *p++ = '\0';
+               if(!isdigit((int)(*q)) || (i = strtol(q, &end, 10)) < 0 || *end) {
+                       free(s);
+                       return false;
+               }
+               out->entries[entry++] = (unsigned)i;
+               q = p;
+       }
+       FLAC__ASSERT(entry == out->num_entries);
+
+       free(s);
+       return true;
+}
+
+FLAC__bool parse_block_type(const char *in, Argument_BlockType *out)
+{
+       char *p, *q, *r, *s;
+       unsigned entry;
+
+       if(*in == '\0')
+               return false;
+
+       s = local_strdup(in);
+
+       /* first count the entries */
+       for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ','))
+               ;
+
+       /* make space */
+       FLAC__ASSERT(out->num_entries > 0);
+       if(0 == (out->entries = (Argument_BlockTypeEntry*)safe_malloc_mul_2op_(sizeof(Argument_BlockTypeEntry), /*times*/out->num_entries)))
+               die("out of memory allocating space for option list");
+
+       /* load 'em up */
+       entry = 0;
+       q = s;
+       while(q) {
+               FLAC__ASSERT(entry < out->num_entries);
+               if(0 != (p = strchr(q, ',')))
+                       *p++ = 0;
+               r = strchr(q, ':');
+               if(r)
+                       *r++ = '\0';
+               if(0 != r && 0 != strcmp(q, "APPLICATION")) {
+                       free(s);
+                       return false;
+               }
+               if(0 == strcmp(q, "STREAMINFO")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_STREAMINFO;
+               }
+               else if(0 == strcmp(q, "PADDING")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_PADDING;
+               }
+               else if(0 == strcmp(q, "APPLICATION")) {
+                       out->entries[entry].type = FLAC__METADATA_TYPE_APPLICATION;
+                       out->entries[entry].filter_application_by_id = (0 != r);
+                       if(0 != r) {
+                               if(strlen(r) == 4) {
+                                       strcpy(out->entries[entry].application_id, r);
+                               }
+                               else if(strlen(r) == 10 && strncmp(r, "0x", 2) == 0 && strspn(r+2, "0123456789ABCDEFabcdef") == 8) {
+                                       FLAC__uint32 x = strtoul(r+2, 0, 16);
+                                       out->entries[entry].application_id[3] = (FLAC__byte)(x & 0xff);
+                                       out->entries[entry].application_id[2] = (FLAC__byte)((x>>=8) & 0xff);
+                                       out->entries[entry].application_id[1] = (FLAC__byte)((x>>=8) & 0xff);
+                                       out->entries[entry].application_id[0] = (FLAC__byte)((x>>=8) & 0xff);
+                               }
+                               else {
+                                       free(s);
+                                       return false;
+                               }
+                       }
+                       entry++;
+               }
+               else if(0 == strcmp(q, "SEEKTABLE")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_SEEKTABLE;
+               }
+               else if(0 == strcmp(q, "VORBIS_COMMENT")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               }
+               else if(0 == strcmp(q, "CUESHEET")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_CUESHEET;
+               }
+               else if(0 == strcmp(q, "PICTURE")) {
+                       out->entries[entry++].type = FLAC__METADATA_TYPE_PICTURE;
+               }
+               else {
+                       free(s);
+                       return false;
+               }
+               q = p;
+       }
+       FLAC__ASSERT(entry == out->num_entries);
+
+       free(s);
+       return true;
+}
+
+FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out)
+{
+       if(0 == strcmp(in, "binary"))
+               out->is_binary = true;
+       else if(0 == strcmp(in, "text"))
+               out->is_binary = false;
+       else
+               return false;
+       return true;
+}
+
+FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out)
+{
+       if(0 == strcmp(in, "hexdump"))
+               *out = true;
+       else if(0 == strcmp(in, "text"))
+               *out = false;
+       else
+               return false;
+       return true;
+}
+
+void undocumented_warning(const char *opt)
+{
+       fprintf(stderr, "WARNING: undocmented option --%s should be used with caution,\n         only for repairing a damaged STREAMINFO block\n", opt);
+}
diff --git a/src/metaflac/options.h b/src/metaflac/options.h
new file mode 100644 (file)
index 0000000..244a8d0
--- /dev/null
@@ -0,0 +1,215 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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 metaflac__options_h
+#define metaflac__options_h
+
+#include "FLAC/format.h"
+
+#if 0
+/*[JEC] was:#if HAVE_GETOPT_LONG*/
+/*[JEC] see flac/include/share/getopt.h as to why the change */
+#  include <getopt.h>
+#else
+#  include "share/getopt.h"
+#endif
+
+extern struct share__option long_options_[];
+
+typedef enum {
+       OP__SHOW_MD5SUM,
+       OP__SHOW_MIN_BLOCKSIZE,
+       OP__SHOW_MAX_BLOCKSIZE,
+       OP__SHOW_MIN_FRAMESIZE,
+       OP__SHOW_MAX_FRAMESIZE,
+       OP__SHOW_SAMPLE_RATE,
+       OP__SHOW_CHANNELS,
+       OP__SHOW_BPS,
+       OP__SHOW_TOTAL_SAMPLES,
+       OP__SET_MD5SUM,
+       OP__SET_MIN_BLOCKSIZE,
+       OP__SET_MAX_BLOCKSIZE,
+       OP__SET_MIN_FRAMESIZE,
+       OP__SET_MAX_FRAMESIZE,
+       OP__SET_SAMPLE_RATE,
+       OP__SET_CHANNELS,
+       OP__SET_BPS,
+       OP__SET_TOTAL_SAMPLES,
+       OP__SHOW_VC_VENDOR,
+       OP__SHOW_VC_FIELD,
+       OP__REMOVE_VC_ALL,
+       OP__REMOVE_VC_FIELD,
+       OP__REMOVE_VC_FIRSTFIELD,
+       OP__SET_VC_FIELD,
+       OP__IMPORT_VC_FROM,
+       OP__EXPORT_VC_TO,
+       OP__IMPORT_CUESHEET_FROM,
+       OP__EXPORT_CUESHEET_TO,
+       OP__IMPORT_PICTURE_FROM,
+       OP__EXPORT_PICTURE_TO,
+       OP__ADD_SEEKPOINT,
+       OP__ADD_REPLAY_GAIN,
+       OP__ADD_PADDING,
+       OP__LIST,
+       OP__APPEND,
+       OP__REMOVE,
+       OP__REMOVE_ALL,
+       OP__MERGE_PADDING,
+       OP__SORT_PADDING
+} OperationType;
+
+typedef enum {
+       ARG__BLOCK_NUMBER,
+       ARG__BLOCK_TYPE,
+       ARG__EXCEPT_BLOCK_TYPE,
+       ARG__DATA_FORMAT,
+       ARG__FROM_FILE
+} ArgumentType;
+
+typedef struct {
+       FLAC__byte value[16];
+} Argument_StreaminfoMD5;
+
+typedef struct {
+       FLAC__uint32 value;
+} Argument_StreaminfoUInt32;
+
+typedef struct {
+       FLAC__uint64 value;
+} Argument_StreaminfoUInt64;
+
+typedef struct {
+       char *value;
+} Argument_VcFieldName;
+
+typedef struct {
+       char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */
+       char *field_name;
+       /* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
+       unsigned field_value_length;
+       char *field_value;
+       FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */
+} Argument_VcField;
+
+typedef struct {
+       char *value;
+} Argument_String;
+
+typedef struct {
+       unsigned num_entries;
+       unsigned *entries;
+} Argument_BlockNumber;
+
+typedef struct {
+       FLAC__MetadataType type;
+       char application_id[4]; /* only relevant if type == FLAC__STREAM_METADATA_TYPE_APPLICATION */
+       FLAC__bool filter_application_by_id;
+} Argument_BlockTypeEntry;
+
+typedef struct {
+       unsigned num_entries;
+       Argument_BlockTypeEntry *entries;
+} Argument_BlockType;
+
+typedef struct {
+       FLAC__bool is_binary;
+} Argument_DataFormat;
+
+typedef struct {
+       char *file_name;
+} Argument_FromFile;
+
+typedef struct {
+       char *specification;
+} Argument_AddSeekpoint;
+
+typedef struct {
+       char *filename;
+       Argument_AddSeekpoint *add_seekpoint_link;
+} Argument_ImportCuesheetFrom;
+
+typedef struct {
+       char *filename;
+       const Argument_BlockNumber *block_number_link; /* may be NULL to mean 'first PICTURE block' */
+} Argument_ExportPictureTo;
+
+typedef struct {
+       unsigned length;
+} Argument_AddPadding;
+
+typedef struct {
+       OperationType type;
+       union {
+               Argument_StreaminfoMD5 streaminfo_md5;
+               Argument_StreaminfoUInt32 streaminfo_uint32;
+               Argument_StreaminfoUInt64 streaminfo_uint64;
+               Argument_VcFieldName vc_field_name;
+               Argument_VcField vc_field;
+               Argument_String filename;
+               Argument_String specification;
+               Argument_ImportCuesheetFrom import_cuesheet_from;
+               Argument_ExportPictureTo export_picture_to;
+               Argument_AddSeekpoint add_seekpoint;
+               Argument_AddPadding add_padding;
+       } argument;
+} Operation;
+
+typedef struct {
+       ArgumentType type;
+       union {
+               Argument_BlockNumber block_number;
+               Argument_BlockType block_type;
+               Argument_DataFormat data_format;
+               Argument_FromFile from_file;
+       } value;
+} Argument;
+
+typedef struct {
+       FLAC__bool preserve_modtime;
+       FLAC__bool prefix_with_filename;
+       FLAC__bool utf8_convert;
+       FLAC__bool use_padding;
+       FLAC__bool cued_seekpoints;
+       FLAC__bool show_long_help;
+       FLAC__bool show_version;
+       FLAC__bool application_data_format_is_hexdump;
+       struct {
+               Operation *operations;
+               unsigned num_operations;
+               unsigned capacity;
+       } ops;
+       struct {
+               struct {
+                       unsigned num_shorthand_ops;
+                       unsigned num_major_ops;
+                       FLAC__bool has_block_type;
+                       FLAC__bool has_except_block_type;
+               } checks;
+               Argument *arguments;
+               unsigned num_arguments;
+               unsigned capacity;
+       } args;
+       unsigned num_files;
+       char **filenames;
+} CommandLineOptions;
+
+void init_options(CommandLineOptions *options);
+FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options);
+void free_options(CommandLineOptions *options);
+
+#endif
diff --git a/src/metaflac/usage.c b/src/metaflac/usage.c
new file mode 100644 (file)
index 0000000..02cfaf2
--- /dev/null
@@ -0,0 +1,325 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "usage.h"
+#include "FLAC/format.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+static void usage_header(FILE *out)
+{
+       fprintf(out, "==============================================================================\n");
+       fprintf(out, "metaflac - Command-line FLAC metadata editor version %s\n", FLAC__VERSION_STRING);
+       fprintf(out, "Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson\n");
+       fprintf(out, "\n");
+       fprintf(out, "This program is free software; you can redistribute it and/or\n");
+       fprintf(out, "modify it under the terms of the GNU General Public License\n");
+       fprintf(out, "as published by the Free Software Foundation; either version 2\n");
+       fprintf(out, "of the License, or (at your option) any later version.\n");
+       fprintf(out, "\n");
+       fprintf(out, "This program is distributed in the hope that it will be useful,\n");
+       fprintf(out, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+       fprintf(out, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
+       fprintf(out, "GNU General Public License for more details.\n");
+       fprintf(out, "\n");
+       fprintf(out, "You should have received a copy of the GNU General Public License\n");
+       fprintf(out, "along with this program; if not, write to the Free Software\n");
+       fprintf(out, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n");
+       fprintf(out, "==============================================================================\n");
+}
+
+static void usage_summary(FILE *out)
+{
+       fprintf(out, "Usage:\n");
+       fprintf(out, "  metaflac [options] [operations] FLACfile [FLACfile ...]\n");
+       fprintf(out, "\n");
+       fprintf(out, "Use metaflac to list, add, remove, or edit metadata in one or more FLAC files.\n");
+       fprintf(out, "You may perform one major operation, or many shorthand operations at a time.\n");
+       fprintf(out, "\n");
+       fprintf(out, "Options:\n");
+       fprintf(out, "--preserve-modtime    Preserve the original modification time in spite of edits\n");
+       fprintf(out, "--with-filename       Prefix each output line with the FLAC file name\n");
+       fprintf(out, "                      (the default if more than one FLAC file is specified)\n");
+       fprintf(out, "--no-filename         Do not prefix each output line with the FLAC file name\n");
+       fprintf(out, "                      (the default if only one FLAC file is specified)\n");
+       fprintf(out, "--no-utf8-convert     Do not convert tags from UTF-8 to local charset,\n");
+       fprintf(out, "                      or vice versa.  This is useful for scripts, and setting\n");
+       fprintf(out, "                      tags in situations where the locale is wrong.\n");
+       fprintf(out, "--dont-use-padding    By default metaflac tries to use padding where possible\n");
+       fprintf(out, "                      to avoid rewriting the entire file if the metadata size\n");
+       fprintf(out, "                      changes.  Use this option to tell metaflac to not take\n");
+       fprintf(out, "                      advantage of padding this way.\n");
+}
+
+int short_usage(const char *message, ...)
+{
+       va_list args;
+
+       if(message) {
+               va_start(args, message);
+
+               (void) vfprintf(stderr, message, args);
+
+               va_end(args);
+
+       }
+       usage_header(stderr);
+       fprintf(stderr, "\n");
+       fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n");
+       fprintf(stderr, "\n");
+       usage_summary(stderr);
+
+       return message? 1 : 0;
+}
+
+int long_usage(const char *message, ...)
+{
+       FILE *out = (message? stderr : stdout);
+       va_list args;
+
+       if(message) {
+               va_start(args, message);
+
+               (void) vfprintf(stderr, message, args);
+
+               va_end(args);
+
+       }
+       usage_header(out);
+       fprintf(out, "\n");
+       usage_summary(out);
+       fprintf(out, "\n");
+       fprintf(out, "Shorthand operations:\n");
+       fprintf(out, "--show-md5sum         Show the MD5 signature from the STREAMINFO block.\n");
+       fprintf(out, "--show-min-blocksize  Show the minimum block size from the STREAMINFO block.\n");
+       fprintf(out, "--show-max-blocksize  Show the maximum block size from the STREAMINFO block.\n");
+       fprintf(out, "--show-min-framesize  Show the minimum frame size from the STREAMINFO block.\n");
+       fprintf(out, "--show-max-framesize  Show the maximum frame size from the STREAMINFO block.\n");
+       fprintf(out, "--show-sample-rate    Show the sample rate from the STREAMINFO block.\n");
+       fprintf(out, "--show-channels       Show the number of channels from the STREAMINFO block.\n");
+       fprintf(out, "--show-bps            Show the # of bits per sample from the STREAMINFO block.\n");
+       fprintf(out, "--show-total-samples  Show the total # of samples from the STREAMINFO block.\n");
+       fprintf(out, "\n");
+       fprintf(out, "--show-vendor-tag     Show the vendor string from the VORBIS_COMMENT block.\n");
+       fprintf(out, "--show-tag=NAME       Show all tags where the the field name matches 'NAME'.\n");
+       fprintf(out, "--remove-tag=NAME     Remove all tags whose field name is 'NAME'.\n");
+       fprintf(out, "--remove-first-tag=NAME  Remove first tag whose field name is 'NAME'.\n");
+       fprintf(out, "--remove-all-tags     Remove all tags, leaving only the vendor string.\n");
+       fprintf(out, "--set-tag=FIELD       Add a tag.  The FIELD must comply with the Vorbis comment\n");
+       fprintf(out, "                      spec, of the form \"NAME=VALUE\".  If there is currently\n");
+       fprintf(out, "                      no tag block, one will be created.\n");
+       fprintf(out, "--set-tag-from-file=FIELD   Like --set-tag, except the VALUE is a filename\n");
+       fprintf(out, "                      whose contents will be read verbatim to set the tag value.\n");
+       fprintf(out, "                      Unless --no-utf8-convert is specified, the contents will\n");
+       fprintf(out, "                      be converted to UTF-8 from the local charset.  This can\n");
+       fprintf(out, "                      be used to store a cuesheet in a tag (e.g.\n");
+       fprintf(out, "                      --set-tag-from-file=\"CUESHEET=image.cue\").  Do not try\n");
+       fprintf(out, "                      to store binary data in tag fields!  Use APPLICATION\n");
+       fprintf(out, "                      blocks for that.\n");
+       fprintf(out, "--import-tags-from=FILE Import tags from a file.  Use '-' for stdin.  Each line\n");
+       fprintf(out, "                      should be of the form NAME=VALUE.  Multi-line comments\n");
+       fprintf(out, "                      are currently not supported.  Specify --remove-all-tags\n");
+       fprintf(out, "                      and/or --no-utf8-convert before --import-tags-from if\n");
+       fprintf(out, "                      necessary.  If FILE is '-' (stdin), only one FLAC file\n");
+       fprintf(out, "                      may be specified.\n");
+       fprintf(out, "--export-tags-to=FILE Export tags to a file.  Use '-' for stdout.  Each line\n");
+       fprintf(out, "                      will be of the form NAME=VALUE.  Specify\n");
+       fprintf(out, "                      --no-utf8-convert if necessary.\n");
+       fprintf(out, "--import-cuesheet-from=FILE  Import a cuesheet from a file.  Use '-' for stdin.\n");
+       fprintf(out, "                      Only one FLAC file may be specified.  A seekpoint will be\n");
+       fprintf(out, "                      added for each index point in the cuesheet to the\n");
+       fprintf(out, "                      SEEKTABLE unless --no-cued-seekpoints is specified.\n");
+       fprintf(out, "--export-cuesheet-to=FILE  Export CUESHEET block to a cuesheet file, suitable\n");
+       fprintf(out, "                      for use by CD authoring software.  Use '-' for stdout.\n");
+       fprintf(out, "                      Only one FLAC file may be specified on the command line.\n");
+       fprintf(out, "--import-picture-from=FILENAME|SPECIFICATION  Import a picture and store it in a\n");
+       fprintf(out, "                      PICTURE block.  Either a filename for the picture file or\n");
+       fprintf(out, "                      a more complete specification form can be used.  The\n");
+       fprintf(out, "                      SPECIFICATION is a string whose parts are separated by |\n");
+       fprintf(out, "                      characters.  Some parts may be left empty to invoke\n");
+       fprintf(out, "                      default values.  FILENAME is just shorthand for\n");
+       fprintf(out, "                      \"||||FILENAME\".  The format of SPECIFICATION is:\n");
+       fprintf(out, "         [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n");
+       fprintf(out, "           TYPE is optional; it is a number from one of:\n");
+       fprintf(out, "              0: Other\n");
+       fprintf(out, "              1: 32x32 pixels 'file icon' (PNG only)\n");
+       fprintf(out, "              2: Other file icon\n");
+       fprintf(out, "              3: Cover (front)\n");
+       fprintf(out, "              4: Cover (back)\n");
+       fprintf(out, "              5: Leaflet page\n");
+       fprintf(out, "              6: Media (e.g. label side of CD)\n");
+       fprintf(out, "              7: Lead artist/lead performer/soloist\n");
+       fprintf(out, "              8: Artist/performer\n");
+       fprintf(out, "              9: Conductor\n");
+       fprintf(out, "             10: Band/Orchestra\n");
+       fprintf(out, "             11: Composer\n");
+       fprintf(out, "             12: Lyricist/text writer\n");
+       fprintf(out, "             13: Recording Location\n");
+       fprintf(out, "             14: During recording\n");
+       fprintf(out, "             15: During performance\n");
+       fprintf(out, "             16: Movie/video screen capture\n");
+       fprintf(out, "             17: A bright coloured fish\n");
+       fprintf(out, "             18: Illustration\n");
+       fprintf(out, "             19: Band/artist logotype\n");
+       fprintf(out, "             20: Publisher/Studio logotype\n");
+       fprintf(out, "             The default is 3 (front cover).  There may only be one picture each\n");
+       fprintf(out, "             of type 1 and 2 in a file.\n");
+       fprintf(out, "           MIME-TYPE is optional; if left blank, it will be detected from the\n");
+       fprintf(out, "             file.  For best compatibility with players, use pictures with MIME\n");
+       fprintf(out, "             type image/jpeg or image/png.  The MIME type can also be --> to\n");
+       fprintf(out, "             mean that FILE is actually a URL to an image, though this use is\n");
+       fprintf(out, "             discouraged.\n");
+       fprintf(out, "           DESCRIPTION is optional; the default is an empty string\n");
+       fprintf(out, "           The next part specfies the resolution and color information.  If\n");
+       fprintf(out, "             the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n");
+       fprintf(out, "             usually leave this empty and they can be detected from the file.\n");
+       fprintf(out, "             Otherwise, you must specify the width in pixels, height in pixels,\n");
+       fprintf(out, "             and color depth in bits-per-pixel.  If the image has indexed colors\n");
+       fprintf(out, "             you should also specify the number of colors used.\n");
+       fprintf(out, "           FILE is the path to the picture file to be imported, or the URL if\n");
+       fprintf(out, "             MIME type is -->\n");
+       fprintf(out, "--export-picture-to=FILE  Export PICTURE block to a file.  Use '-' for stdout.\n");
+       fprintf(out, "                      Only one FLAC file may be specified.  The first PICTURE\n");
+       fprintf(out, "                      block will be exported unless --export-picture-to is\n");
+       fprintf(out, "                      preceded by a --block-number=# option to specify the exact\n");
+       fprintf(out, "                      metadata block to extract.  Note that the block number is\n");
+       fprintf(out, "                      the one shown by --list.\n");
+       fprintf(out, "--add-replay-gain     Calculates the title and album gains/peaks of the given\n");
+       fprintf(out, "                      FLAC files as if all the files were part of one album,\n");
+       fprintf(out, "                      then stores them in the VORBIS_COMMENT block.  The tags\n");
+       fprintf(out, "                      are the same as those used by vorbisgain.  Existing\n");
+       fprintf(out, "                      ReplayGain tags will be replaced.  If only one FLAC file\n");
+       fprintf(out, "                      is given, the album and title gains will be the same.\n");
+       fprintf(out, "                      Since this operation requires two passes, it is always\n");
+       fprintf(out, "                      executed last, after all other operations have been\n");
+       fprintf(out, "                      completed and written to disk.  All FLAC files specified\n");
+       fprintf(out, "                      must have the same resolution, sample rate, and number\n");
+       fprintf(out, "                      of channels.  The sample rate must be one of 8, 11.025,\n");
+       fprintf(out, "                      12, 16, 22.05, 24, 32, 44.1, or 48 kHz.\n");
+       fprintf(out, "--remove-replay-gain  Removes the ReplayGain tags.\n");
+       fprintf(out, "--add-seekpoint={#|X|#x|#s}  Add seek points to a SEEKTABLE block\n");
+       fprintf(out, "       #  : a specific sample number for a seek point\n");
+       fprintf(out, "       X  : a placeholder point (always goes at the end of the SEEKTABLE)\n");
+       fprintf(out, "       #x : # evenly spaced seekpoints, the first being at sample 0\n");
+       fprintf(out, "       #s : a seekpoint every # seconds; # does not have to be a whole number\n");
+       fprintf(out, "                      If no SEEKTABLE block exists, one will be created.  If\n");
+       fprintf(out, "                      one already exists, points will be added to the existing\n");
+       fprintf(out, "                      table, and any duplicates will be turned into placeholder\n");
+       fprintf(out, "                      points.  You may use many --add-seekpoint options; the\n");
+       fprintf(out, "                      resulting SEEKTABLE will be the unique-ified union of\n");
+       fprintf(out, "                      all such values.  Example: --add-seekpoint=100x\n");
+       fprintf(out, "                      --add-seekpoint=3.5s will add 100 evenly spaced\n");
+       fprintf(out, "                      seekpoints and a seekpoint every 3.5 seconds.\n");
+       fprintf(out, "--add-padding=length  Add a padding block of the given length (in bytes).\n");
+       fprintf(out, "                      The overall length of the new block will be 4 + length;\n");
+       fprintf(out, "                      the extra 4 bytes is for the metadata block header.\n");
+       fprintf(out, "\n");
+       fprintf(out, "Major operations:\n");
+       fprintf(out, "--version\n");
+       fprintf(out, "    Show the metaflac version number.\n");
+       fprintf(out, "--list\n");
+       fprintf(out, "    List the contents of one or more metadata blocks to stdout.  By default,\n");
+       fprintf(out, "    all metadata blocks are listed in text format.  Use the following options\n");
+       fprintf(out, "    to change this behavior:\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --block-number=#[,#[...]]\n");
+       fprintf(out, "    An optional comma-separated list of block numbers to display.  The first\n");
+       fprintf(out, "    block, the STREAMINFO block, is block 0.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --block-type=type[,type[...]]\n");
+       fprintf(out, "    --except-block-type=type[,type[...]]\n");
+       fprintf(out, "    An optional comma-separated list of block types to be included or ignored\n");
+       fprintf(out, "    with this option.  Use only one of --block-type or --except-block-type.\n");
+       fprintf(out, "    The valid block types are: STREAMINFO, PADDING, APPLICATION, SEEKTABLE,\n");
+       fprintf(out, "    VORBIS_COMMENT.  You may narrow down the types of APPLICATION blocks\n");
+       fprintf(out, "    displayed as follows:\n");
+       fprintf(out, "        APPLICATION:abcd        The APPLICATION block(s) whose textual repre-\n");
+       fprintf(out, "                                sentation of the 4-byte ID is \"abcd\"\n");
+       fprintf(out, "        APPLICATION:0xXXXXXXXX  The APPLICATION block(s) whose hexadecimal big-\n");
+       fprintf(out, "                                endian representation of the 4-byte ID is\n");
+       fprintf(out, "                                \"0xXXXXXXXX\".  For the example \"abcd\" above the\n");
+       fprintf(out, "                                hexadecimal equivalalent is 0x61626364\n");
+       fprintf(out, "\n");
+       fprintf(out, "    NOTE: if both --block-number and --[except-]block-type are specified,\n");
+       fprintf(out, "          the result is the logical AND of both arguments.\n");
+       fprintf(out, "\n");
+#if 0
+       /*@@@ not implemented yet */
+       fprintf(out, "    --data-format=binary|text\n");
+       fprintf(out, "    By default a human-readable text representation of the data is displayed.\n");
+       fprintf(out, "    You may specify --data-format=binary to dump the raw binary form of each\n");
+       fprintf(out, "    metadata block.  The output can be read in using a subsequent call to\n");
+       fprintf(out, "    "metaflac --append --from-file=..."\n");
+       fprintf(out, "\n");
+#endif
+       fprintf(out, "    --application-data-format=hexdump|text\n");
+       fprintf(out, "    If the application block you are displaying contains binary data but your\n");
+       fprintf(out, "    --data-format=text, you can display a hex dump of the application data\n");
+       fprintf(out, "    contents instead using --application-data-format=hexdump\n");
+       fprintf(out, "\n");
+#if 0
+       /*@@@ not implemented yet */
+       fprintf(out, "--append\n");
+       fprintf(out, "    Insert a metadata block from a file.  The input file must be in the same\n");
+       fprintf(out, "    format as generated with --list.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --block-number=#\n");
+       fprintf(out, "    Specify the insertion point (defaults to last block).  The new block will\n");
+       fprintf(out, "    be added after the given block number.  This prevents the illegal insertion\n");
+       fprintf(out, "    of a block before the first STREAMINFO block.  You may not --append another\n");
+       fprintf(out, "    STREAMINFO block.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --from-file=filename\n");
+       fprintf(out, "    Mandatory 'option' to specify the input file containing the block contents.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --data-format=binary|text\n");
+       fprintf(out, "    By default the block contents are assumed to be in binary format.  You can\n");
+       fprintf(out, "    override this by specifying --data-format=text\n");
+       fprintf(out, "\n");
+#endif
+       fprintf(out, "--remove\n");
+       fprintf(out, "    Remove one or more metadata blocks from the metadata.  Unless\n");
+       fprintf(out, "    --dont-use-padding is specified, the blocks will be replaced with padding.\n");
+       fprintf(out, "    You may not remove the STREAMINFO block.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    --block-number=#[,#[...]]\n");
+       fprintf(out, "    --block-type=type[,type[...]]\n");
+       fprintf(out, "    --except-block-type=type[,type[...]]\n");
+       fprintf(out, "    See --list above for usage.\n");
+       fprintf(out, "\n");
+       fprintf(out, "    NOTE: if both --block-number and --[except-]block-type are specified,\n");
+       fprintf(out, "          the result is the logical AND of both arguments.\n");
+       fprintf(out, "\n");
+       fprintf(out, "--remove-all\n");
+       fprintf(out, "    Remove all metadata blocks (except the STREAMINFO block) from the\n");
+       fprintf(out, "    metadata.  Unless --dont-use-padding is specified, the blocks will be\n");
+       fprintf(out, "    replaced with padding.\n");
+       fprintf(out, "\n");
+       fprintf(out, "--merge-padding\n");
+       fprintf(out, "    Merge adjacent PADDING blocks into single blocks.\n");
+       fprintf(out, "\n");
+       fprintf(out, "--sort-padding\n");
+       fprintf(out, "    Move all PADDING blocks to the end of the metadata and merge them into a\n");
+       fprintf(out, "    single block.\n");
+
+       return message? 1 : 0;
+}
diff --git a/src/metaflac/usage.h b/src/metaflac/usage.h
new file mode 100644 (file)
index 0000000..8ad091c
--- /dev/null
@@ -0,0 +1,25 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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 metaflac__usage_h
+#define metaflac__usage_h
+
+int short_usage(const char *message, ...);
+int long_usage(const char *message, ...);
+
+#endif
diff --git a/src/metaflac/utils.c b/src/metaflac/utils.c
new file mode 100644 (file)
index 0000000..cdd823c
--- /dev/null
@@ -0,0 +1,258 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/utf8.h"
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void die(const char *message)
+{
+       FLAC__ASSERT(0 != message);
+       fprintf(stderr, "ERROR: %s\n", message);
+       exit(1);
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#endif
+
+char *local_strdup(const char *source)
+{
+       char *ret;
+       FLAC__ASSERT(0 != source);
+       if(0 == (ret = strdup(source)))
+               die("out of memory during strdup()");
+       return ret;
+}
+
+void local_strcat(char **dest, const char *source)
+{
+       size_t ndest, nsource;
+
+       FLAC__ASSERT(0 != dest);
+       FLAC__ASSERT(0 != source);
+
+       ndest = *dest? strlen(*dest) : 0;
+       nsource = strlen(source);
+
+       if(nsource == 0)
+               return;
+
+       *dest = (char*)safe_realloc_add_3op_(*dest, ndest, /*+*/nsource, /*+*/1);
+       if(0 == *dest)
+               die("out of memory growing string");
+       strcpy((*dest)+ndest, source);
+}
+
+void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent)
+{
+       unsigned i, left = bytes;
+       const FLAC__byte *b = buf;
+
+       for(i = 0; i < bytes; i += 16) {
+               printf("%s%s%s%08X: "
+                       "%02X %02X %02X %02X %02X %02X %02X %02X "
+                       "%02X %02X %02X %02X %02X %02X %02X %02X "
+                       "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+                       filename? filename:"", filename? ":":"",
+                       indent, i,
+                       left >  0? (unsigned char)b[ 0] : 0,
+                       left >  1? (unsigned char)b[ 1] : 0,
+                       left >  2? (unsigned char)b[ 2] : 0,
+                       left >  3? (unsigned char)b[ 3] : 0,
+                       left >  4? (unsigned char)b[ 4] : 0,
+                       left >  5? (unsigned char)b[ 5] : 0,
+                       left >  6? (unsigned char)b[ 6] : 0,
+                       left >  7? (unsigned char)b[ 7] : 0,
+                       left >  8? (unsigned char)b[ 8] : 0,
+                       left >  9? (unsigned char)b[ 9] : 0,
+                       left > 10? (unsigned char)b[10] : 0,
+                       left > 11? (unsigned char)b[11] : 0,
+                       left > 12? (unsigned char)b[12] : 0,
+                       left > 13? (unsigned char)b[13] : 0,
+                       left > 14? (unsigned char)b[14] : 0,
+                       left > 15? (unsigned char)b[15] : 0,
+                       (left >  0) ? (isprint(b[ 0]) ? b[ 0] : '.') : ' ',
+                       (left >  1) ? (isprint(b[ 1]) ? b[ 1] : '.') : ' ',
+                       (left >  2) ? (isprint(b[ 2]) ? b[ 2] : '.') : ' ',
+                       (left >  3) ? (isprint(b[ 3]) ? b[ 3] : '.') : ' ',
+                       (left >  4) ? (isprint(b[ 4]) ? b[ 4] : '.') : ' ',
+                       (left >  5) ? (isprint(b[ 5]) ? b[ 5] : '.') : ' ',
+                       (left >  6) ? (isprint(b[ 6]) ? b[ 6] : '.') : ' ',
+                       (left >  7) ? (isprint(b[ 7]) ? b[ 7] : '.') : ' ',
+                       (left >  8) ? (isprint(b[ 8]) ? b[ 8] : '.') : ' ',
+                       (left >  9) ? (isprint(b[ 9]) ? b[ 9] : '.') : ' ',
+                       (left > 10) ? (isprint(b[10]) ? b[10] : '.') : ' ',
+                       (left > 11) ? (isprint(b[11]) ? b[11] : '.') : ' ',
+                       (left > 12) ? (isprint(b[12]) ? b[12] : '.') : ' ',
+                       (left > 13) ? (isprint(b[13]) ? b[13] : '.') : ' ',
+                       (left > 14) ? (isprint(b[14]) ? b[14] : '.') : ' ',
+                       (left > 15) ? (isprint(b[15]) ? b[15] : '.') : ' '
+               );
+               left -= 16;
+               b += 16;
+   }
+}
+
+void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...)
+{
+       const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status(chain);
+       va_list args;
+
+       FLAC__ASSERT(0 != format);
+
+       va_start(args, format);
+
+       (void) vfprintf(stderr, format, args);
+
+       va_end(args);
+
+       fprintf(stderr, ", status = \"%s\"\n", FLAC__Metadata_ChainStatusString[status]);
+
+       if(status == FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
+               fprintf(stderr, "\n"
+                       "The FLAC file could not be opened.  Most likely the file does not exist\n"
+                       "or is not readable.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE) {
+               fprintf(stderr, "\n"
+                       "The file does not appear to be a FLAC file.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE) {
+               fprintf(stderr, "\n"
+                       "The FLAC file does not have write permissions.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_BAD_METADATA) {
+               fprintf(stderr, "\n"
+                       "The metadata to be writted does not conform to the FLAC metadata\n"
+                       "specifications.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_READ_ERROR) {
+               fprintf(stderr, "\n"
+                       "There was an error while reading the FLAC file.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR) {
+               fprintf(stderr, "\n"
+                       "There was an error while writing FLAC file; most probably the disk is\n"
+                       "full.\n"
+               );
+       }
+       else if(status == FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR) {
+               fprintf(stderr, "\n"
+                       "There was an error removing the temporary FLAC file.\n"
+               );
+       }
+}
+
+FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation)
+{
+       static const char * const violations[] = {
+               "field name contains invalid character",
+               "field contains no '=' character"
+       };
+
+       char *p, *q, *s;
+
+       if(0 != field)
+               *field = local_strdup(field_ref);
+
+       s = local_strdup(field_ref);
+
+       if(0 == (p = strchr(s, '='))) {
+               free(s);
+               *violation = violations[1];
+               return false;
+       }
+       *p++ = '\0';
+
+       for(q = s; *q; q++) {
+               if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
+                       free(s);
+                       *violation = violations[0];
+                       return false;
+               }
+       }
+
+       *name = local_strdup(s);
+       *value = local_strdup(p);
+       *length = strlen(p);
+
+       free(s);
+       return true;
+}
+
+void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f)
+{
+       if(0 != entry->entry) {
+               if(filename)
+                       fprintf(f, "%s:", filename);
+
+               if(!raw) {
+                       /*
+                        * WATCHOUT: comments that contain an embedded null will
+                        * be truncated by utf_decode().
+                        */
+                       char *converted;
+
+                       if(utf8_decode((const char *)entry->entry, &converted) >= 0) {
+                               (void) local_fwrite(converted, 1, strlen(converted), f);
+                               free(converted);
+                       }
+                       else {
+                               (void) local_fwrite(entry->entry, 1, entry->length, f);
+                       }
+               }
+               else {
+                       (void) local_fwrite(entry->entry, 1, entry->length, f);
+               }
+       }
+
+       putc('\n', f);
+}
+
+void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f)
+{
+       unsigned i;
+       const unsigned field_name_length = (0 != field_name)? strlen(field_name) : 0;
+
+       for(i = 0; i < num_entries; i++) {
+               if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry[i], field_name, field_name_length))
+                       write_vc_field(filename, entry + i, raw, f);
+       }
+}
diff --git a/src/metaflac/utils.h b/src/metaflac/utils.h
new file mode 100644 (file)
index 0000000..111d10c
--- /dev/null
@@ -0,0 +1,41 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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 metaflac__utils_h
+#define metaflac__utils_h
+
+#include "FLAC/metadata.h"
+#include <stdio.h> /* for FILE */
+
+void die(const char *message);
+#ifdef FLAC__VALGRIND_TESTING
+size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+#else
+#define local_fwrite fwrite
+#endif
+char *local_strdup(const char *source);
+void local_strcat(char **dest, const char *source);
+void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent);
+void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...);
+
+FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation);
+
+void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f);
+void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f);
+
+#endif
diff --git a/src/monkeys_audio_utilities/Makefile.am b/src/monkeys_audio_utilities/Makefile.am
new file mode 100644 (file)
index 0000000..3cfe69a
--- /dev/null
@@ -0,0 +1,18 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = flac_mac flac_ren
diff --git a/src/monkeys_audio_utilities/flac_mac/Makefile.am b/src/monkeys_audio_utilities/flac_mac/Makefile.am
new file mode 100644 (file)
index 0000000..fef6138
--- /dev/null
@@ -0,0 +1,21 @@
+#  flac_mac - wedge utility to add FLAC support to Monkey's Audio
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       flac_mac.dsp \
+       flac_mac.vcproj \
+       main.c
diff --git a/src/monkeys_audio_utilities/flac_mac/flac_mac.dsp b/src/monkeys_audio_utilities/flac_mac/flac_mac.dsp
new file mode 100644 (file)
index 0000000..79d6871
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="flac_mac" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=flac_mac - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac_mac.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac_mac.mak" CFG="flac_mac - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "flac_mac - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "flac_mac - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "flac_mac - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "flac_mac - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "flac_mac - Win32 Release"\r
+# Name "flac_mac - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/monkeys_audio_utilities/flac_mac/flac_mac.vcproj b/src/monkeys_audio_utilities/flac_mac/flac_mac.vcproj
new file mode 100644 (file)
index 0000000..6f9973a
--- /dev/null
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="flac_mac"\r
+       ProjectGUID="{4cefbc7e-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="flac_mac"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/monkeys_audio_utilities/flac_mac/main.c b/src/monkeys_audio_utilities/flac_mac/main.c
new file mode 100644 (file)
index 0000000..99109c0
--- /dev/null
@@ -0,0 +1,208 @@
+/* flac_mac - wedge utility to add FLAC support to Monkey's Audio\r
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+\r
+/*\r
+ * This program can be used to allow FLAC to masquerade as one of the other\r
+ * supported lossless codecs in Monkey's Audio.  See the documentation for\r
+ * how to do this.\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include<stdio.h>\r
+#include<stdlib.h>\r
+#include<string.h>\r
+#include<wtypes.h>\r
+#include<process.h>\r
+#include<winbase.h>\r
+\r
+static int execit(char *prog, char *args);\r
+static int forkit(char *prog, char *args);\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       int flac_return_val = 0, opt_arg = 1, from_arg = -1, to_arg = -1, flac_level = 5, i;\r
+       char prog[MAX_PATH], cmdline[MAX_PATH*2], from[MAX_PATH], to[MAX_PATH], macdir[MAX_PATH], options[256], *p;\r
+       enum { WAVPACK, RKAU, SHORTEN } codec;\r
+\r
+       /* get the directory where MAC external codecs reside */\r
+       if(0 != (p = strrchr(argv[0],'\\'))) {\r
+               strcpy(macdir, argv[0]);\r
+               *(strrchr(macdir,'\\')+1) = '\0';\r
+       }\r
+       else {\r
+               strcpy(macdir, "");\r
+       }\r
+\r
+       /* determine which codec we were called as and parse the options */\r
+       if(p == 0)\r
+               p = argv[0];\r
+       else\r
+               p++;\r
+       if(0 == strnicmp(p, "short", 5)) {\r
+               codec = SHORTEN;\r
+       }\r
+       else if(0 == strnicmp(p, "rkau", 4)) {\r
+               codec = RKAU;\r
+               if(argv[1][0] == '-' && argv[1][1] == 'l') {\r
+                       opt_arg = 2;\r
+                       switch(argv[1][2]) {\r
+                               case '1': flac_level = 1; break;\r
+                               case '2': flac_level = 5; break;\r
+                               case '3': flac_level = 8; break;\r
+                       }\r
+               }\r
+       }\r
+       else if(0 == strnicmp(p, "wavpack", 7)) {\r
+               codec = WAVPACK;\r
+               if(argv[1][0] == '-') {\r
+                       opt_arg = 2;\r
+                       switch(argv[1][1]) {\r
+                               case 'f': flac_level = 1; break;\r
+                               case 'h': flac_level = 8; break;\r
+                               default: opt_arg = 1;\r
+                       }\r
+               }\r
+       }\r
+       else {\r
+               return -5;\r
+       }\r
+\r
+       /* figure out which arguments are the source and destination files */\r
+       for(i = 1; i < argc; i++)\r
+               if(argv[i][0] != '-') {\r
+                       from_arg = i++;\r
+                       break;\r
+               }\r
+       for( ; i < argc; i++)\r
+               if(argv[i][0] != '-') {\r
+                       to_arg = i++;\r
+                       break;\r
+               }\r
+       if(to_arg < 0)\r
+               return -4;\r
+\r
+       /* build the command to call flac with */\r
+       sprintf(prog, "%sflac.exe", macdir);\r
+       sprintf(options, "-%d", flac_level);\r
+       for(i = opt_arg; i < argc; i++)\r
+               if(argv[i][0] == '-') {\r
+                       strcat(options, " ");\r
+                       strcat(options, argv[i]);\r
+               }\r
+       sprintf(cmdline, "\"%s\" %s -o \"%s\" \"%s\"", prog, options, argv[to_arg], argv[from_arg]);\r
+\r
+       flac_return_val = execit(prog, cmdline);\r
+\r
+       /*\r
+        * Now that flac has finished, we need to fork a process that will rename\r
+        * the resulting file with the correct extension once MAC has moved it to\r
+        * it's final resting place.\r
+        */\r
+       if(0 == flac_return_val) {\r
+               /* get the destination directory, if any */\r
+               if(0 != (p = strchr(argv[to_arg],'\\'))) {\r
+                       strcpy(from, argv[to_arg]);\r
+                       *(strrchr(from,'\\')+1) = '\0';\r
+               }\r
+               else {\r
+                       strcpy(from, "");\r
+               }\r
+\r
+               /* for the full 'from' and 'to' paths for the renamer process */\r
+               p = strrchr(argv[from_arg],'\\');\r
+               strcat(from, p? p+1 : argv[from_arg]);\r
+               strcpy(to, from);\r
+               if(0 == strchr(from,'.'))\r
+                       return -3;\r
+               switch(codec) {\r
+                       case SHORTEN: strcpy(strrchr(from,'.'), ".shn"); break;\r
+                       case WAVPACK: strcpy(strrchr(from,'.'), ".wv"); break;\r
+                       case RKAU: strcpy(strrchr(from,'.'), ".rka"); break;\r
+               }\r
+               strcpy(strrchr(to,'.'), ".flac");\r
+\r
+               sprintf(prog, "%sflac_ren.exe", macdir);\r
+               sprintf(cmdline, "\"%s\" \"%s\" \"%s\"", prog, from, to);\r
+\r
+               flac_return_val = forkit(prog, cmdline);\r
+       }\r
+\r
+       return flac_return_val;\r
+}\r
+\r
+int execit(char *prog, char *args)\r
+{\r
+       BOOL ok;\r
+       STARTUPINFO startup_info;\r
+       PROCESS_INFORMATION proc_info;\r
+\r
+       GetStartupInfo(&startup_info);\r
+\r
+       ok = CreateProcess(\r
+               prog,\r
+               args,\r
+               0, /*process security attributes*/\r
+               0, /*thread security attributes*/\r
+               FALSE,\r
+               0, /*dwCreationFlags*/\r
+               0, /*environment*/\r
+               0, /*lpCurrentDirectory*/\r
+               &startup_info,\r
+               &proc_info\r
+       );\r
+       if(ok) {\r
+               DWORD dw;\r
+               dw = WaitForSingleObject(proc_info.hProcess, INFINITE);\r
+               ok = (dw != 0xFFFFFFFF);\r
+               CloseHandle(proc_info.hThread);\r
+               CloseHandle(proc_info.hProcess);\r
+       }\r
+\r
+       return ok? 0 : -1;\r
+}\r
+\r
+int forkit(char *prog, char *args)\r
+{\r
+       BOOL ok;\r
+       STARTUPINFO startup_info;\r
+       PROCESS_INFORMATION proc_info;\r
+\r
+       GetStartupInfo(&startup_info);\r
+\r
+       ok = CreateProcess(\r
+               prog,\r
+               args,\r
+               0, /*process security attributes*/\r
+               0, /*thread security attributes*/\r
+               FALSE,\r
+               DETACHED_PROCESS, /*dwCreationFlags*/\r
+               0, /*environment*/\r
+               0, /*lpCurrentDirectory*/\r
+               &startup_info,\r
+               &proc_info\r
+       );\r
+       if(ok) {\r
+               CloseHandle(proc_info.hThread);\r
+               CloseHandle(proc_info.hProcess);\r
+       }\r
+\r
+       return ok? 0 : -2;\r
+}\r
diff --git a/src/monkeys_audio_utilities/flac_ren/Makefile.am b/src/monkeys_audio_utilities/flac_ren/Makefile.am
new file mode 100644 (file)
index 0000000..ddb7d2f
--- /dev/null
@@ -0,0 +1,21 @@
+#  flac_ren - renamer part of utility to add FLAC support to Monkey's Audio
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       flac_ren.dsp \
+       flac_ren.vcproj \
+       main.c
diff --git a/src/monkeys_audio_utilities/flac_ren/flac_ren.dsp b/src/monkeys_audio_utilities/flac_ren/flac_ren.dsp
new file mode 100644 (file)
index 0000000..0e8cdc7
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="flac_ren" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=flac_ren - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac_ren.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "flac_ren.mak" CFG="flac_ren - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "flac_ren - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "flac_ren - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "flac_ren - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "flac_ren - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "flac_ren - Win32 Release"\r
+# Name "flac_ren - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/monkeys_audio_utilities/flac_ren/flac_ren.vcproj b/src/monkeys_audio_utilities/flac_ren/flac_ren.vcproj
new file mode 100644 (file)
index 0000000..e12d711
--- /dev/null
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="flac_ren"\r
+       ProjectGUID="{4cefbc7f-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="flac_ren"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/monkeys_audio_utilities/flac_ren/main.c b/src/monkeys_audio_utilities/flac_ren/main.c
new file mode 100644 (file)
index 0000000..fa84983
--- /dev/null
@@ -0,0 +1,39 @@
+/* flac_ren - renamer part of utility to add FLAC support to Monkey's Audio\r
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include <io.h>\r
+#include <sys/stat.h>\r
+#include <wtypes.h>\r
+#include <winbase.h>\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       struct stat s;\r
+\r
+       /* wait till the 'from' file has reached its final destination */\r
+       do {\r
+               Sleep(2000);\r
+       } while(stat(argv[1], &s) < 0);\r
+\r
+       /* now rename it */\r
+       return rename(argv[1], argv[2]);\r
+}\r
diff --git a/src/plugin_common/Makefile.am b/src/plugin_common/Makefile.am
new file mode 100644 (file)
index 0000000..e2915a7
--- /dev/null
@@ -0,0 +1,48 @@
+#  plugin_common - Routines common to several plugins
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libplugin_common.la
+
+noinst_HEADERS = \
+       all.h \
+       charset.h \
+       defs.h \
+       dither.h \
+       replaygain.h \
+       tags.h
+
+libplugin_common_la_SOURCES = \
+       charset.c \
+       dither.c \
+       replaygain.c \
+       tags.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       README \
+       plugin_common_static.dsp \
+       plugin_common_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/plugin_common/Makefile.lite b/src/plugin_common/Makefile.lite
new file mode 100644 (file)
index 0000000..987bae8
--- /dev/null
@@ -0,0 +1,36 @@
+#  plugin_common - Routines common to several plugins
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#
+# GNU makefile
+#
+
+topdir = ../..
+
+LIB_NAME = libplugin_common
+INCLUDES = -I$(topdir)/include -I$(HOME)/local/include
+DEFINES  = 
+
+SRCS_C = \
+       charset.c \
+       dither.c \
+       replaygain.c \
+       tags.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/plugin_common/README b/src/plugin_common/README
new file mode 100644 (file)
index 0000000..5a33526
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains a convenience library of routines that are
+common to the plugins.
diff --git a/src/plugin_common/all.h b/src/plugin_common/all.h
new file mode 100644 (file)
index 0000000..e987dd0
--- /dev/null
@@ -0,0 +1,26 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__ALL_H
+#define FLAC__PLUGIN_COMMON__ALL_H
+
+#include "charset.h"
+#include "dither.h"
+#include "tags.h"
+
+#endif
diff --git a/src/plugin_common/charset.c b/src/plugin_common/charset.c
new file mode 100644 (file)
index 0000000..cc82669
--- /dev/null
@@ -0,0 +1,157 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Only slightly modified charset.c from:
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  HÃ¥vard KvÃ¥len <havardk@xmms.org>
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "charset.h"
+
+
+/*************
+ * Functions *
+ *************/
+
+char* FLAC_plugin__charset_get_current (void)
+{
+       char *charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+       if (!charset)
+               charset = nl_langinfo(CODESET);
+#endif
+       if (!charset)
+               charset = "ISO-8859-1";
+
+       return charset;
+}
+
+
+#ifdef HAVE_ICONV
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+       size_t outleft, outsize, length;
+       iconv_t cd;
+       char *out, *outptr;
+       const char *input = string;
+
+       if (!string)
+               return NULL;
+
+       length = strlen(string);
+
+       if ((cd = iconv_open(to, from)) == (iconv_t)-1)
+       {
+#ifdef DEBUG
+               fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to);
+#endif
+               return strdup(string);
+       }
+
+       /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */
+       /* + 1 for nul in case len == 1 */
+       outsize = ((length + 3) & ~3) + 1;
+       if(outsize < length) /* overflow check */
+               return NULL;
+       out = (char*)malloc(outsize);
+       outleft = outsize - 1;
+       outptr = out;
+
+retry:
+       if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)(-1))
+       {
+               int used;
+               switch (errno)
+               {
+                       case E2BIG:
+                               used = outptr - out;
+                               if((outsize - 1) * 2 + 1 <= outsize) { /* overflow check */
+                                       free(out);
+                                       return NULL;
+                               }
+                               outsize = (outsize - 1) * 2 + 1;
+                               out = realloc(out, outsize);
+                               outptr = out + used;
+                               outleft = outsize - 1 - used;
+                               goto retry;
+                       case EINVAL:
+                               break;
+                       case EILSEQ:
+                               /* Invalid sequence, try to get the rest of the string */
+                               input++;
+                               length = strlen(input);
+                               goto retry;
+                       default:
+#ifdef DEBUG
+                               fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno));
+#endif
+                               break;
+               }
+       }
+       *outptr = '\0';
+
+       iconv_close(cd);
+       return out;
+}
+#else
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+       (void)from, (void)to;
+       if (!string)
+               return NULL;
+       return strdup(string);
+}
+#endif
+
+#ifdef HAVE_ICONV
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+       iconv_t cd;
+
+       if ((cd=iconv_open(to,from)) == (iconv_t)-1)
+       {
+               /* Conversion not supported */
+               return 0;
+       }
+       iconv_close(cd);
+       return 1;
+}
+#else
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+       (void)from, (void)to;
+       return 1;
+}
+#endif
diff --git a/src/plugin_common/charset.h b/src/plugin_common/charset.h
new file mode 100644 (file)
index 0000000..7ea2838
--- /dev/null
@@ -0,0 +1,39 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * Only slightly modified charset.h from:
+ * charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kvè™±en <havardk@xmms.org>
+ *
+ *  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__PLUGIN_COMMON__CHARSET_H
+#define FLAC__PLUGIN_COMMON__CHARSET_H
+
+
+/**************
+ * Prototypes *
+ **************/
+
+char *FLAC_plugin__charset_get_current(void);
+char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to);
+
+/* returns 1 for success, 0 for failure or no iconv */
+int FLAC_plugin__charset_test_conversion(char *from, char *to);
+
+#endif
diff --git a/src/plugin_common/defs.h b/src/plugin_common/defs.h
new file mode 100644 (file)
index 0000000..0cc9b4b
--- /dev/null
@@ -0,0 +1,24 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DEFS_H
+#define FLAC__PLUGIN_COMMON__DEFS_H
+
+#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2
+
+#endif
diff --git a/src/plugin_common/dither.c b/src/plugin_common/dither.c
new file mode 100644 (file)
index 0000000..538a280
--- /dev/null
@@ -0,0 +1,262 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * dithering routine derived from (other GPLed source):
+ * mad - MPEG audio decoder
+ * Copyright (C) 2000-2001 Robert Leslie
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "dither.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+
+/* 32-bit pseudo-random number generator
+ *
+ * @@@ According to Miroslav, this one is poor quality, the one from the
+ * @@@ original replaygain code is much better
+ */
+static FLaC__INLINE FLAC__uint32 prng(FLAC__uint32 state)
+{
+       return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
+}
+
+/* dither routine derived from MAD winamp plugin */
+
+typedef struct {
+       FLAC__int32 error[3];
+       FLAC__int32 random;
+} dither_state;
+
+static FLaC__INLINE FLAC__int32 linear_dither(unsigned source_bps, unsigned target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX)
+{
+       unsigned scalebits;
+       FLAC__int32 output, mask, random;
+
+       FLAC__ASSERT(source_bps < 32);
+       FLAC__ASSERT(target_bps <= 24);
+       FLAC__ASSERT(target_bps <= source_bps);
+
+       /* noise shape */
+       sample += dither->error[0] - dither->error[1] + dither->error[2];
+
+       dither->error[2] = dither->error[1];
+       dither->error[1] = dither->error[0] / 2;
+
+       /* bias */
+       output = sample + (1L << (source_bps - target_bps - 1));
+
+       scalebits = source_bps - target_bps;
+       mask = (1L << scalebits) - 1;
+
+       /* dither */
+       random = (FLAC__int32)prng(dither->random);
+       output += (random & mask) - (dither->random & mask);
+
+       dither->random = random;
+
+       /* clip */
+       if(output > MAX) {
+               output = MAX;
+
+               if(sample > MAX)
+                       sample = MAX;
+       }
+       else if(output < MIN) {
+               output = MIN;
+
+               if(sample < MIN)
+                       sample = MIN;
+       }
+
+       /* quantize */
+       output &= ~mask;
+
+       /* error feedback */
+       dither->error[0] = sample - output;
+
+       /* scale */
+       return output >> scalebits;
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
+{
+       static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+       FLAC__byte * const start = data;
+       FLAC__int32 sample;
+       const FLAC__int32 *input_;
+       unsigned samples, channel;
+       const unsigned bytes_per_sample = target_bps / 8;
+       const unsigned incr = bytes_per_sample * channels;
+
+       FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+       FLAC__ASSERT(source_bps < 32);
+       FLAC__ASSERT(target_bps <= 24);
+       FLAC__ASSERT(target_bps <= source_bps);
+       FLAC__ASSERT((source_bps & 7) == 0);
+       FLAC__ASSERT((target_bps & 7) == 0);
+
+       if(source_bps != target_bps) {
+               const FLAC__int32 MIN = -(1L << (source_bps - 1));
+               const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+               for(channel = 0; channel < channels; channel++) {
+                       
+                       samples = wide_samples;
+                       data = start + bytes_per_sample * channel;
+                       input_ = input[channel];
+
+                       while(samples--) {
+                               sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+                               switch(target_bps) {
+                                       case 8:
+                                               data[0] = sample ^ 0x80;
+                                               break;
+                                       case 16:
+                                               data[0] = (FLAC__byte)(sample >> 8);
+                                               data[1] = (FLAC__byte)sample;
+                                               break;
+                                       case 24:
+                                               data[0] = (FLAC__byte)(sample >> 16);
+                                               data[1] = (FLAC__byte)(sample >> 8);
+                                               data[2] = (FLAC__byte)sample;
+                                               break;
+                               }
+
+                               data += incr;
+                       }
+               }
+       }
+       else {
+               for(channel = 0; channel < channels; channel++) {
+                       samples = wide_samples;
+                       data = start + bytes_per_sample * channel;
+                       input_ = input[channel];
+
+                       while(samples--) {
+                               sample = *input_++;
+
+                               switch(target_bps) {
+                                       case 8:
+                                               data[0] = sample ^ 0x80;
+                                               break;
+                                       case 16:
+                                               data[0] = (FLAC__byte)(sample >> 8);
+                                               data[1] = (FLAC__byte)sample;
+                                               break;
+                                       case 24:
+                                               data[0] = (FLAC__byte)(sample >> 16);
+                                               data[1] = (FLAC__byte)(sample >> 8);
+                                               data[2] = (FLAC__byte)sample;
+                                               break;
+                               }
+
+                               data += incr;
+                       }
+               }
+       }
+
+       return wide_samples * channels * (target_bps/8);
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
+{
+       static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+       FLAC__byte * const start = data;
+       FLAC__int32 sample;
+       const FLAC__int32 *input_;
+       unsigned samples, channel;
+       const unsigned bytes_per_sample = target_bps / 8;
+       const unsigned incr = bytes_per_sample * channels;
+
+       FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+       FLAC__ASSERT(source_bps < 32);
+       FLAC__ASSERT(target_bps <= 24);
+       FLAC__ASSERT(target_bps <= source_bps);
+       FLAC__ASSERT((source_bps & 7) == 0);
+       FLAC__ASSERT((target_bps & 7) == 0);
+
+       if(source_bps != target_bps) {
+               const FLAC__int32 MIN = -(1L << (source_bps - 1));
+               const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+               for(channel = 0; channel < channels; channel++) {
+                       
+                       samples = wide_samples;
+                       data = start + bytes_per_sample * channel;
+                       input_ = input[channel];
+
+                       while(samples--) {
+                               sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+                               switch(target_bps) {
+                                       case 8:
+                                               data[0] = sample ^ 0x80;
+                                               break;
+                                       case 24:
+                                               data[2] = (FLAC__byte)(sample >> 16);
+                                               /* fall through */
+                                       case 16:
+                                               data[1] = (FLAC__byte)(sample >> 8);
+                                               data[0] = (FLAC__byte)sample;
+                               }
+
+                               data += incr;
+                       }
+               }
+       }
+       else {
+               for(channel = 0; channel < channels; channel++) {
+                       samples = wide_samples;
+                       data = start + bytes_per_sample * channel;
+                       input_ = input[channel];
+
+                       while(samples--) {
+                               sample = *input_++;
+
+                               switch(target_bps) {
+                                       case 8:
+                                               data[0] = sample ^ 0x80;
+                                               break;
+                                       case 24:
+                                               data[2] = (FLAC__byte)(sample >> 16);
+                                               /* fall through */
+                                       case 16:
+                                               data[1] = (FLAC__byte)(sample >> 8);
+                                               data[0] = (FLAC__byte)sample;
+                               }
+
+                               data += incr;
+                       }
+               }
+       }
+
+       return wide_samples * channels * (target_bps/8);
+}
diff --git a/src/plugin_common/dither.h b/src/plugin_common/dither.h
new file mode 100644 (file)
index 0000000..ad94bae
--- /dev/null
@@ -0,0 +1,29 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DITHER_H
+#define FLAC__PLUGIN_COMMON__DITHER_H
+
+#include <stdlib.h> /* for size_t */
+#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */
+#include "FLAC/ordinals.h"
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
+
+#endif
diff --git a/src/plugin_common/plugin_common_static.dsp b/src/plugin_common/plugin_common_static.dsp
new file mode 100644 (file)
index 0000000..7415c8d
--- /dev/null
@@ -0,0 +1,128 @@
+# Microsoft Developer Studio Project File - Name="plugin_common_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=plugin_common_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "plugin_common_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "plugin_common_static.mak" CFG="plugin_common_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "plugin_common_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "plugin_common_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "plugin_common"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "plugin_common_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "plugin_common_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "plugin_common_static - Win32 Release"\r
+# Name "plugin_common_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp"\r
+# Begin Source File\r
+\r
+SOURCE=.\charset.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\dither.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\replaygain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\tags.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\all.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\charset.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\dither.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\replaygain.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\tags.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/plugin_common/plugin_common_static.vcproj b/src/plugin_common/plugin_common_static.vcproj
new file mode 100644 (file)
index 0000000..710ed96
--- /dev/null
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="plugin_common_static"\r
+       ProjectGUID="{4cefbc88-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="plugin_common_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\all.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\charset.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\defs.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\dither.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\replaygain.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\tags.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\charset.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\dither.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\replaygain.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\tags.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/plugin_common/replaygain.c b/src/plugin_common/replaygain.c
new file mode 100644 (file)
index 0000000..5ad59c8
--- /dev/null
@@ -0,0 +1,64 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "replaygain.h"
+#include "FLAC/ordinals.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+FLAC__bool FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                                 double *reference, FLAC__bool *reference_set,
+                                                 double *track_gain, FLAC__bool *track_gain_set,
+                                                 double *album_gain, FLAC__bool *album_gain_set,
+                                                 double *track_peak, FLAC__bool *track_peak_set,
+                                                 double *album_peak, FLAC__bool *album_peak_set)
+{
+       FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
+       FLAC__bool ret = false;
+
+       *track_gain_set = *album_gain_set = *track_peak_set = *album_peak_set = false;
+
+       if(0 != iterator) {
+               if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+                       FLAC__bool got_vorbis_comments = false;
+                       ret = true;
+                       do {
+                               if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+                                       FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
+                                       if(0 != block) {
+                                               if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/false, /*strict=*/true, reference, track_gain, track_peak)) {
+                                                       *reference_set = *track_gain_set = *track_peak_set = true;
+                                               }
+                                               if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/true, /*strict=*/true, reference, album_gain, album_peak)) {
+                                                       *reference_set = *album_gain_set = *album_peak_set = true;
+                                               }
+                                               FLAC__metadata_object_delete(block);
+                                               got_vorbis_comments = true;
+                                       }
+                               }
+                       } while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
+               }
+               FLAC__metadata_simple_iterator_delete(iterator);
+       }
+       return ret;
+}
diff --git a/src/plugin_common/replaygain.h b/src/plugin_common/replaygain.h
new file mode 100644 (file)
index 0000000..528312e
--- /dev/null
@@ -0,0 +1,32 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * 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__PLUGIN_COMMON__REPLAYGAIN_H
+#define FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set);
+
+#endif
diff --git a/src/plugin_common/tags.c b/src/plugin_common/tags.c
new file mode 100644 (file)
index 0000000..befc848
--- /dev/null
@@ -0,0 +1,358 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tags.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/alloc.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+
+static FLaC__INLINE size_t local__wide_strlen(const FLAC__uint16 *s)
+{
+       size_t n = 0;
+       while(*s++)
+               n++;
+       return n;
+}
+
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ *   http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ *   http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static FLaC__INLINE size_t local__utf8len(const FLAC__byte *utf8)
+{
+       FLAC__ASSERT(0 != utf8);
+       if ((utf8[0] & 0x80) == 0) {
+               return 1;
+       }
+       else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+               if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+                       return 0;
+               return 2;
+       }
+       else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+                       return 0;
+               /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+               if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+                       return 0;
+               if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+                       return 0;
+               return 3;
+       }
+       else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 4;
+       }
+       else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 5;
+       }
+       else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+               if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+                       return 0;
+               return 6;
+       }
+       else {
+               return 0;
+       }
+}
+
+
+static FLaC__INLINE size_t local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2)
+{
+       const size_t len = local__utf8len(utf8);
+
+       FLAC__ASSERT(0 != ucs2);
+
+       if (len == 1)
+               *ucs2 = *utf8;
+       else if (len == 2)
+               *ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
+       else if (len == 3)
+               *ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
+       else
+               *ucs2 = '?';
+
+       return len;
+}
+
+static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, unsigned length)
+{
+       FLAC__uint16 *out;
+       size_t chars = 0;
+
+       FLAC__ASSERT(0 != src);
+
+       /* calculate length */
+       {
+               const unsigned char *s, *end;
+               for (s=(const unsigned char *)src, end=s+length; s<end; chars++) {
+                       const unsigned n = local__utf8len(s);
+                       if (n == 0)
+                               return 0;
+                       s += n;
+               }
+               FLAC__ASSERT(s == end);
+       }
+
+       /* allocate */
+       out = (FLAC__uint16*)safe_malloc_mul_2op_(chars, /*times*/sizeof(FLAC__uint16));
+       if (0 == out) {
+               FLAC__ASSERT(0);
+               return 0;
+       }
+
+       /* convert */
+       {
+               const unsigned char *s = (const unsigned char *)src;
+               FLAC__uint16 *u = out;
+               for ( ; chars; chars--)
+                       s += local__utf8_to_ucs2(s, u++);
+       }
+
+       return out;
+}
+
+static FLaC__INLINE size_t local__ucs2len(FLAC__uint16 ucs2)
+{
+       if (ucs2 < 0x0080)
+               return 1;
+       else if (ucs2 < 0x0800)
+               return 2;
+       else
+               return 3;
+}
+
+static FLaC__INLINE size_t local__ucs2_to_utf8(FLAC__uint16 ucs2, FLAC__byte *utf8)
+{
+       if (ucs2 < 0x080) {
+               utf8[0] = (FLAC__byte)ucs2;
+               return 1;
+       }
+       else if (ucs2 < 0x800) {
+               utf8[0] = 0xc0 | (ucs2 >> 6);
+               utf8[1] = 0x80 | (ucs2 & 0x3f);
+               return 2;
+       }
+       else {
+               utf8[0] = 0xe0 | (ucs2 >> 12);
+               utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
+               utf8[2] = 0x80 | (ucs2 & 0x3f);
+               return 3;
+       }
+}
+
+static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, unsigned length)
+{
+       char *out;
+       size_t len = 0, n;
+
+       FLAC__ASSERT(0 != src);
+
+       /* calculate length */
+       {
+               unsigned i;
+               for (i = 0; i < length; i++) {
+                       n = local__ucs2len(src[i]);
+                       if(len + n < len) /* overflow check */
+                               return 0;
+                       len += n;
+               }
+       }
+
+       /* allocate */
+       out = (char*)safe_malloc_mul_2op_(len, /*times*/sizeof(char));
+       if (0 == out)
+               return 0;
+
+       /* convert */
+       {
+               unsigned char *u = (unsigned char *)out;
+               for ( ; *src; src++)
+                       u += local__ucs2_to_utf8(*src, u);
+               local__ucs2_to_utf8(*src, u);
+       }
+
+       return out;
+}
+
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags)
+{
+       if(!FLAC__metadata_get_tags(filename, tags))
+               if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
+                       return false;
+       return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags)
+{
+       FLAC__Metadata_Chain *chain;
+       FLAC__Metadata_Iterator *iterator;
+       FLAC__StreamMetadata *block;
+       FLAC__bool got_vorbis_comments = false;
+       FLAC__bool ok;
+
+       if(0 == (chain = FLAC__metadata_chain_new()))
+               return false;
+
+       if(!FLAC__metadata_chain_read(chain, filename)) {
+               FLAC__metadata_chain_delete(chain);
+               return false;
+       }
+
+       if(0 == (iterator = FLAC__metadata_iterator_new())) {
+               FLAC__metadata_chain_delete(chain);
+               return false;
+       }
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       do {
+               if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+                       got_vorbis_comments = true;
+       } while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator));
+
+       if(0 == (block = FLAC__metadata_object_clone(tags))) {
+               FLAC__metadata_chain_delete(chain);
+               FLAC__metadata_iterator_delete(iterator);
+               return false;
+       }
+
+       if(got_vorbis_comments)
+               ok = FLAC__metadata_iterator_set_block(iterator, block);
+       else
+               ok = FLAC__metadata_iterator_insert_block_after(iterator, block);
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       if(ok) {
+               FLAC__metadata_chain_sort_padding(chain);
+               ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true);
+       }
+
+       FLAC__metadata_chain_delete(chain);
+
+       return ok;
+}
+
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags)
+{
+       FLAC__metadata_object_delete(*tags);
+       *tags = 0;
+}
+
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name)
+{
+       const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name);
+       return (i < 0? 0 : strchr((const char *)tags->data.vorbis_comment.comments[i].entry, '=')+1);
+}
+
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name)
+{
+       const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+       if(0 == utf8)
+               return 0;
+       return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */
+}
+
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name)
+{
+       return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name);
+}
+
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags)
+{
+       int n = (int)tags->data.vorbis_comment.num_comments;
+       if(n > 0) {
+               if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0))
+                       n = -1;
+       }
+       return n;
+}
+
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator)
+{
+       int i;
+
+       FLAC__ASSERT(0 != tags);
+       FLAC__ASSERT(0 != name);
+       FLAC__ASSERT(0 != value);
+
+       if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) {
+               FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i;
+               const size_t value_len = strlen(value);
+               const size_t separator_len = strlen(separator);
+               FLAC__byte *new_entry;
+               if(0 == (new_entry = (FLAC__byte*)safe_realloc_add_4op_(entry->entry, entry->length, /*+*/value_len, /*+*/separator_len, /*+*/1)))
+                       return false;
+               memcpy(new_entry+entry->length, separator, separator_len);
+               entry->length += separator_len;
+               memcpy(new_entry+entry->length, value, value_len);
+               entry->length += value_len;
+               new_entry[entry->length] = '\0';
+               entry->entry = new_entry;
+       }
+       else {
+               FLAC__StreamMetadata_VorbisComment_Entry entry;
+               if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value))
+                       return false;
+               FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false);
+       }
+       return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all)
+{
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+       FLAC__ASSERT(0 != tags);
+       FLAC__ASSERT(0 != name);
+       FLAC__ASSERT(0 != value);
+
+       {
+               char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */
+               if(0 == utf8)
+                       return false;
+               if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) {
+                       free(utf8);
+                       return false;
+               }
+               free(utf8);
+       }
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false))
+               return false;
+       return true;
+}
diff --git a/src/plugin_common/tags.h b/src/plugin_common/tags.h
new file mode 100644 (file)
index 0000000..7888767
--- /dev/null
@@ -0,0 +1,74 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__TAGS_H
+#define FLAC__PLUGIN_COMMON__TAGS_H
+
+#include "FLAC/format.h"
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags);
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags);
+
+/*
+ * Deletes the tags object and sets '*tags' to NULL.
+ */
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags);
+
+/*
+ * Gets the value (in UTF-8) of the first tag with the given name (NULL if no
+ * such tag exists).
+ */
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Gets the value (in UCS-2) of the first tag with the given name (NULL if no
+ * such tag exists).
+ *
+ * NOTE: the returned string is malloc()ed and must be free()d by the caller.
+ */
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags with the given 'name'.  Returns the number of tags removed,
+ * or -1 on memory allocation error.
+ */
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags.  Returns the number of tags removed, or -1 on memory
+ * allocation error.
+ */
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UTF-8.  If
+ * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the
+ * first such tag's value is appended with separator, then value.
+ */
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UCS-2.  If 'tags'
+ * already contains a tag or tags for 'name', then they will be replaced
+ * according to 'replace_all': if 'replace_all' is false, only the first such
+ * tag will be replaced; if true, all matching tags will be replaced by the one
+ * new tag. 
+ */
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all);
+
+#endif
diff --git a/src/plugin_winamp2/Makefile.am b/src/plugin_winamp2/Makefile.am
new file mode 100644 (file)
index 0000000..401d4d5
--- /dev/null
@@ -0,0 +1,33 @@
+#  in_flac - Winamp2 FLAC input plugin
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+SUBDIRS = include
+
+EXTRA_DIST = \
+       configure.h \
+       configure.c \
+       in_flac.c \
+       in_flac.dsp \
+       in_flac.vcproj \
+       infobox.c \
+       infobox.h \
+       playback.c \
+       playback.h \
+       resource.h \
+       resource.rc \
+       tagz.cpp \
+       tagz.h
diff --git a/src/plugin_winamp2/configure.c b/src/plugin_winamp2/configure.c
new file mode 100644 (file)
index 0000000..400aef2
--- /dev/null
@@ -0,0 +1,428 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include <windows.h>\r
+#include <commctrl.h>\r
+#include <stdio.h>\r
+#include "configure.h"\r
+#include "tagz.h"\r
+#include "resource.h"\r
+#include "share/alloc.h"\r
+\r
+\r
+static char buffer[256];\r
+static char ini_name[MAX_PATH];\r
+\r
+/*\r
+ *  Read/write config\r
+ */\r
+\r
+#define RI(x, def)          (x = GetPrivateProfileInt("FLAC", #x, def, ini_name))\r
+#define WI(x)               WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name)\r
+#define RS(x, n, def)       GetPrivateProfileString("FLAC", #x, def, x, n, ini_name)\r
+#define WS(x)               WritePrivateProfileString("FLAC", #x, x, ini_name)\r
+\r
+static const char default_format[] = "[%artist% - ]$if2(%title%,%filename%)";\r
+static const char default_sep[] = ", ";\r
+\r
+static wchar_t *convert_ansi_to_wide_(const char *src)\r
+{\r
+       int len;\r
+       wchar_t *dest;\r
+\r
+       FLAC__ASSERT(0 != src);\r
+\r
+       len = strlen(src) + 1;\r
+       /* copy */\r
+       dest = safe_malloc_mul_2op_(len, /*times*/sizeof(wchar_t));\r
+       if (dest) mbstowcs(dest, src, len);\r
+       return dest;\r
+}\r
+\r
+void InitConfig()\r
+{\r
+       char *p;\r
+\r
+       GetModuleFileName(NULL, ini_name, sizeof(ini_name));\r
+       p = strrchr(ini_name, '.');\r
+       if (!p) p = ini_name + strlen(ini_name);\r
+       strcpy(p, ".ini");\r
+\r
+       flac_cfg.title.tag_format_w = NULL;\r
+}\r
+\r
+void ReadConfig()\r
+{\r
+       RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format);\r
+       if (flac_cfg.title.tag_format_w)\r
+               free(flac_cfg.title.tag_format_w);\r
+       flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format);\r
+       /* @@@ FIXME: trailing spaces */\r
+       RS(flac_cfg.title.sep, sizeof(flac_cfg.title.sep), default_sep);\r
+       RI(flac_cfg.tag.reserve_space, 1);\r
+\r
+       RI(flac_cfg.display.show_bps, 1);\r
+       RI(flac_cfg.output.misc.stop_err, 0);\r
+       RI(flac_cfg.output.replaygain.enable, 1);\r
+       RI(flac_cfg.output.replaygain.album_mode, 0);\r
+       RI(flac_cfg.output.replaygain.hard_limit, 0);\r
+       RI(flac_cfg.output.replaygain.preamp, 0);\r
+       RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0);\r
+       RI(flac_cfg.output.resolution.replaygain.dither, 0);\r
+       RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1);\r
+       RI(flac_cfg.output.resolution.replaygain.bps_out, 16);\r
+}\r
+\r
+void WriteConfig()\r
+{\r
+       WS(flac_cfg.title.tag_format);\r
+       WI(flac_cfg.tag.reserve_space);\r
+       WS(flac_cfg.title.sep);\r
+\r
+       WI(flac_cfg.display.show_bps);\r
+       WI(flac_cfg.output.misc.stop_err);\r
+       WI(flac_cfg.output.replaygain.enable);\r
+       WI(flac_cfg.output.replaygain.album_mode);\r
+       WI(flac_cfg.output.replaygain.hard_limit);\r
+       WI(flac_cfg.output.replaygain.preamp);\r
+       WI(flac_cfg.output.resolution.normal.dither_24_to_16);\r
+       WI(flac_cfg.output.resolution.replaygain.dither);\r
+       WI(flac_cfg.output.resolution.replaygain.noise_shaping);\r
+       WI(flac_cfg.output.resolution.replaygain.bps_out);\r
+}\r
+\r
+/*\r
+ *  Dialog\r
+ */\r
+\r
+#define PREAMP_RANGE            24\r
+\r
+#define Check(x,y)              CheckDlgButton(hwnd, x, y ? BST_CHECKED : BST_UNCHECKED)\r
+#define GetCheck(x)             (IsDlgButtonChecked(hwnd, x)==BST_CHECKED)\r
+#define GetSel(x)               SendDlgItemMessage(hwnd, x, CB_GETCURSEL, 0, 0)\r
+#define GetPos(x)               SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0)\r
+#define Enable(x,y)             EnableWindow(GetDlgItem(hwnd, x), y)\r
+\r
+static INT_PTR CALLBACK GeneralProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msg)\r
+       {\r
+       /* init */\r
+       case WM_INITDIALOG:\r
+               SendDlgItemMessage(hwnd, IDC_TITLE, EM_LIMITTEXT, 255, 0);\r
+               SendDlgItemMessage(hwnd, IDC_SEP, EM_LIMITTEXT, 15, 0);\r
+\r
+               SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format);\r
+               SetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep);\r
+               Check(IDC_ID3V1, 0);\r
+/*!            Check(IDC_RESERVE, flac_cfg.tag.reserve_space); */\r
+               Check(IDC_BPS, flac_cfg.display.show_bps);\r
+               Check(IDC_ERRORS, flac_cfg.output.misc.stop_err);\r
+               return TRUE;\r
+       /* commands */\r
+       case WM_COMMAND:\r
+               switch (LOWORD(wParam))\r
+               {\r
+               /* ok */\r
+               case IDOK:\r
+                       GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format));\r
+                       if (flac_cfg.title.tag_format_w)\r
+                               free(flac_cfg.title.tag_format_w);\r
+                       GetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep, sizeof(flac_cfg.title.sep));\r
+                       flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format);\r
+\r
+/*!                    flac_cfg.tag.reserve_space = GetCheck(IDC_RESERVE); */\r
+                       flac_cfg.display.show_bps = GetCheck(IDC_BPS);\r
+                       flac_cfg.output.misc.stop_err = GetCheck(IDC_ERRORS);\r
+                       break;\r
+               /* reset */\r
+               case IDC_RESET:\r
+                       Check(IDC_ID3V1, 0);\r
+                       Check(IDC_RESERVE, 1);\r
+                       Check(IDC_BPS, 1);\r
+                       Check(IDC_ERRORS, 0);\r
+                       /* fall throught */\r
+               /* default */\r
+               case IDC_TAGZ_DEFAULT:\r
+                       SetDlgItemText(hwnd, IDC_TITLE, default_format);\r
+                       break;\r
+               /* help */\r
+               case IDC_TAGZ_HELP:\r
+                       MessageBox(hwnd, tagz_manual, "Help", 0);\r
+                       break;\r
+               }\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static void UpdatePreamp(HWND hwnd, HWND hamp)\r
+{\r
+       int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE;\r
+       sprintf(buffer, "%d dB", pos);\r
+       SetDlgItemText(hwnd, IDC_PA, buffer);\r
+}\r
+\r
+static void UpdateRG(HWND hwnd)\r
+{\r
+       int on = GetCheck(IDC_ENABLE);\r
+       Enable(IDC_ALBUM, on);\r
+       Enable(IDC_LIMITER, on);\r
+       Enable(IDC_PREAMP, on);\r
+       Enable(IDC_PA, on);\r
+}\r
+\r
+static void UpdateDither(HWND hwnd)\r
+{\r
+       int on = GetCheck(IDC_DITHERRG);\r
+       Enable(IDC_SHAPE, on);\r
+}\r
+\r
+static INT_PTR CALLBACK OutputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msg)\r
+       {\r
+       /* init */\r
+       case WM_INITDIALOG:\r
+               Check(IDC_ENABLE, flac_cfg.output.replaygain.enable);\r
+               Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode);\r
+               Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);\r
+               Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);\r
+               Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);\r
+               /* prepare preamp slider */\r
+               {\r
+                       HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);\r
+                       SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));\r
+                       SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);\r
+                       UpdatePreamp(hwnd, hamp);\r
+               }\r
+               /* fill comboboxes */\r
+               {\r
+                       HWND hlist = GetDlgItem(hwnd, IDC_TO);\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps");\r
+                       SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0);\r
+\r
+                       hlist = GetDlgItem(hwnd, IDC_SHAPE);\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None");\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low");\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium");\r
+                       SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");\r
+                       SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);\r
+               }\r
+               UpdateRG(hwnd);\r
+               UpdateDither(hwnd);\r
+               return TRUE;\r
+       /* commands */\r
+       case WM_COMMAND:\r
+               switch (LOWORD(wParam))\r
+               {\r
+               /* ok */\r
+               case IDOK:\r
+                       flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);\r
+                       flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);\r
+                       flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);\r
+                       flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE;\r
+                       flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER);\r
+                       flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);\r
+                       flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);\r
+                       flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;\r
+                       break;\r
+               /* reset */\r
+               case IDC_RESET:\r
+                       Check(IDC_ENABLE, 1);\r
+                       Check(IDC_ALBUM, 0);\r
+                       Check(IDC_LIMITER, 0);\r
+                       Check(IDC_DITHER, 0);\r
+                       Check(IDC_DITHERRG, 0);\r
+\r
+                       SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);\r
+                       SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);\r
+                       SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);\r
+\r
+                       UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));\r
+                       UpdateRG(hwnd);\r
+                       UpdateDither(hwnd);\r
+                       break;\r
+               /* active check-boxes */\r
+               case IDC_ENABLE:\r
+                       UpdateRG(hwnd);\r
+                       break;\r
+               case IDC_DITHERRG:\r
+                       UpdateDither(hwnd);\r
+                       break;\r
+               }\r
+               break;\r
+       /* scroller */\r
+       case WM_HSCROLL:\r
+               if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP)\r
+                       UpdatePreamp(hwnd, (HWND)lParam);\r
+               return 0;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+#define NUM_PAGES       2\r
+\r
+typedef struct\r
+{\r
+       HWND htab;\r
+       HWND hdlg;\r
+       RECT r;\r
+       HWND all[NUM_PAGES];\r
+} LOCALDATA;\r
+\r
+static void ScreenToClientRect(HWND hwnd, RECT *rect)\r
+{\r
+       POINT pt = { rect->left, rect->top };\r
+       ScreenToClient(hwnd, &pt);\r
+       rect->left = pt.x;\r
+       rect->top  = pt.y;\r
+\r
+       pt.x = rect->right;\r
+       pt.y = rect->bottom;\r
+       ScreenToClient(hwnd, &pt);\r
+       rect->right  = pt.x;\r
+       rect->bottom = pt.y;\r
+}\r
+\r
+static void SendCommand(HWND hwnd, int command)\r
+{\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       SendMessage(data->hdlg, WM_COMMAND, command, 0);\r
+}\r
+\r
+static void BroadcastCommand(HWND hwnd, int command)\r
+{\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       int i;\r
+\r
+       for (i=0; i<NUM_PAGES; i++)\r
+               SendMessage(data->all[i], WM_COMMAND, command, 0);\r
+}\r
+\r
+static void OnSelChange(HWND hwnd)\r
+{\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       int index = TabCtrl_GetCurSel(data->htab);\r
+       if (index < 0) return;\r
+       /* hide previous */\r
+       if (data->hdlg)\r
+               ShowWindow(data->hdlg, SW_HIDE);\r
+       /* display */\r
+       data->hdlg = data->all[index];\r
+       SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW);\r
+       SetFocus(hwnd);\r
+}\r
+\r
+static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       static activePage = 0;\r
+\r
+       switch (msg)\r
+       {\r
+       /* init */\r
+       case WM_INITDIALOG:\r
+               {\r
+                       LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));\r
+                       HINSTANCE inst = (HINSTANCE)lParam;\r
+                       TCITEM item;\r
+\r
+                       /* init */\r
+                       SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);\r
+                       data->htab = GetDlgItem(hwnd, IDC_TABS);\r
+                       data->hdlg = NULL;\r
+                       /* add pages */\r
+                       item.mask = TCIF_TEXT;\r
+                       data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc);\r
+                       item.pszText = "General";\r
+                       TabCtrl_InsertItem(data->htab, 0, &item);\r
+\r
+                       data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc);\r
+                       item.pszText = "Output";\r
+                       TabCtrl_InsertItem(data->htab, 1, &item);\r
+                       /* get rect (after adding pages) */\r
+                       GetWindowRect(data->htab, &data->r);\r
+                       ScreenToClientRect(hwnd, &data->r);\r
+                       TabCtrl_AdjustRect(data->htab, 0, &data->r);\r
+                       /* simulate item change */\r
+                       TabCtrl_SetCurSel(data->htab, activePage);\r
+                       OnSelChange(hwnd);\r
+               }\r
+               return TRUE;\r
+       /* destory */\r
+       case WM_DESTROY:\r
+               {\r
+                       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+                       int i;\r
+\r
+                       activePage = TabCtrl_GetCurSel(data->htab);\r
+\r
+                       for (i=0; i<NUM_PAGES; i++)\r
+                               DestroyWindow(data->all[i]);\r
+\r
+                       LocalFree(data);\r
+               }\r
+               break;\r
+       /* commands */\r
+       case WM_COMMAND:\r
+               switch (LOWORD(wParam))\r
+               {\r
+               /* ok/cancel */\r
+               case IDOK:\r
+                       BroadcastCommand(hwnd, IDOK);\r
+                       /* fall through */\r
+               case IDCANCEL:\r
+                       EndDialog(hwnd, LOWORD(wParam));\r
+                       return TRUE;\r
+               case IDC_RESET:\r
+                       SendCommand(hwnd, IDC_RESET);\r
+                       break;\r
+               }\r
+               break;\r
+       /* notification */\r
+       case WM_NOTIFY:\r
+               if (LOWORD(wParam) == IDC_TABS)\r
+               {\r
+                       NMHDR *hdr = (NMHDR*)lParam;\r
+\r
+                       switch (hdr->code)\r
+                       {\r
+                       case TCN_SELCHANGE:\r
+                               OnSelChange(hwnd);\r
+                               break;\r
+                       }\r
+               }\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+int DoConfig(HINSTANCE inst, HWND parent)\r
+{\r
+       return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK;\r
+}\r
diff --git a/src/plugin_winamp2/configure.h b/src/plugin_winamp2/configure.h
new file mode 100644 (file)
index 0000000..c1900a9
--- /dev/null
@@ -0,0 +1,49 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#include "playback.h"\r
+\r
+/*\r
+ *  common stuff\r
+ */\r
+\r
+typedef struct {\r
+       struct {\r
+               char tag_format[256];\r
+               char sep[16];\r
+               WCHAR *tag_format_w;\r
+       } title;\r
+       struct {\r
+               BOOL reserve_space;\r
+       } tag;\r
+       struct {\r
+               FLAC__bool show_bps;\r
+       } display;\r
+       output_config_t output;\r
+} flac_config_t;\r
+\r
+extern flac_config_t flac_cfg;\r
+\r
+/*\r
+ *  prototypes\r
+ */\r
+\r
+void InitConfig();\r
+void ReadConfig();\r
+void WriteConfig();\r
+int  DoConfig(HINSTANCE inst, HWND parent);\r
diff --git a/src/plugin_winamp2/in_flac.c b/src/plugin_winamp2/in_flac.c
new file mode 100644 (file)
index 0000000..02f382a
--- /dev/null
@@ -0,0 +1,443 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include <windows.h>\r
+#include <limits.h> /* for INT_MAX */\r
+#include <stdio.h>\r
+\r
+#include "share/alloc.h"\r
+#include "winamp2/in2.h"\r
+#include "configure.h"\r
+#include "infobox.h"\r
+#include "tagz.h"\r
+\r
+#define PLUGIN_VERSION          "1.2.1"\r
+\r
+static In_Module mod_;                      /* the input module (declared near the bottom of this file) */\r
+static char lastfn_[MAX_PATH];              /* currently playing file (used for getting info on the current file) */\r
+flac_config_t flac_cfg;\r
+\r
+static stream_data_struct stream_data_;\r
+static int paused;\r
+static FLAC__StreamDecoder *decoder_;\r
+static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2];\r
+/* (24/8) for max bytes per sample, and 2 for DSPs */\r
+\r
+static HANDLE thread_handle = NULL;         /* the handle to the decode thread */\r
+static DWORD WINAPI DecodeThread(void *b);  /* the decode thread procedure */\r
+\r
+/*\r
+ *  init/quit\r
+ */\r
+\r
+static void init()\r
+{\r
+       decoder_ = FLAC__stream_decoder_new();\r
+       strcpy(lastfn_, "");\r
+\r
+       InitConfig();\r
+       ReadConfig();\r
+       InitInfobox();\r
+}\r
+\r
+static void quit()\r
+{\r
+       WriteConfig();\r
+       DeinitInfobox();\r
+       FLAC_plugin__decoder_delete(decoder_);\r
+       decoder_ = 0;\r
+}\r
+\r
+/*\r
+ *  open/close\r
+ */\r
+\r
+static int isourfile(char *fn) { return 0; }\r
+\r
+static int play(char *fn)\r
+{\r
+       LONGLONG filesize;\r
+       DWORD thread_id;\r
+       int   maxlatency;\r
+       /* checks */\r
+       if (decoder_ == 0) return 1;\r
+       if (!(filesize = FileSize(fn))) return -1;\r
+       /* init decoder */\r
+       if (!FLAC_plugin__decoder_init(decoder_, fn, filesize, &stream_data_, &flac_cfg.output))\r
+               return 1;\r
+       strcpy(lastfn_, fn);\r
+       /* open output */\r
+       maxlatency = mod_.outMod->Open(stream_data_.sample_rate, stream_data_.channels, stream_data_.output_bits_per_sample, -1, -1);\r
+       if (maxlatency < 0)\r
+       {\r
+               FLAC_plugin__decoder_finish(decoder_);\r
+               return 1;\r
+       }\r
+       /* set defaults */\r
+       mod_.outMod->SetVolume(-666);\r
+       mod_.outMod->SetPan(0);\r
+       /* initialize vis stuff */\r
+       mod_.SAVSAInit(maxlatency, stream_data_.sample_rate);\r
+       mod_.VSASetInfo(stream_data_.sample_rate, stream_data_.channels);\r
+       /* set info */\r
+       mod_.SetInfo(stream_data_.average_bps, stream_data_.sample_rate/1000, stream_data_.channels, 1);\r
+       /* start playing thread */\r
+       paused = 0;\r
+       thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);\r
+       if (!thread_handle)     return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+static void stop()\r
+{\r
+       if (thread_handle)\r
+       {\r
+               stream_data_.is_playing = false;\r
+               if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)\r
+               {\r
+                       FLAC_plugin__show_error("Error while stopping decoding thread.");\r
+                       TerminateThread(thread_handle, 0);\r
+               }\r
+               CloseHandle(thread_handle);\r
+               thread_handle = NULL;\r
+       }\r
+\r
+       FLAC_plugin__decoder_finish(decoder_);\r
+       mod_.outMod->Close();\r
+       mod_.SAVSADeInit();\r
+}\r
+\r
+/*\r
+ *  play control\r
+ */\r
+\r
+static void pause()\r
+{\r
+       paused = 1;\r
+       mod_.outMod->Pause(1);\r
+}\r
+\r
+static void unpause()\r
+{\r
+       paused = 0;\r
+       mod_.outMod->Pause(0);\r
+}\r
+\r
+static int ispaused()\r
+{\r
+       return paused;\r
+}\r
+\r
+static int getlength()\r
+{\r
+       return stream_data_.length_in_msec;\r
+}\r
+\r
+static int getoutputtime()\r
+{\r
+       return mod_.outMod->GetOutputTime();\r
+}\r
+\r
+static void setoutputtime(int time_in_ms)\r
+{\r
+       stream_data_.seek_to = time_in_ms;\r
+}\r
+\r
+static void setvolume(int volume)\r
+{\r
+       mod_.outMod->SetVolume(volume);\r
+}\r
+\r
+static void setpan(int pan)\r
+{\r
+       mod_.outMod->SetPan(pan);\r
+}\r
+\r
+static void eq_set(int on, char data[10], int preamp) {}\r
+\r
+/*\r
+ *  playing loop\r
+ */\r
+\r
+static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)\r
+{\r
+       static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];\r
+       char *ptr;\r
+       int size, count;\r
+\r
+       /*\r
+        * Winamp visuals may have problems accepting sample sizes larger than\r
+        * 16 bits, so we reduce the sample size here if necessary.\r
+        */\r
+\r
+       switch(resolution) {\r
+               case 32:\r
+               case 24:\r
+                       size  = resolution / 8;\r
+                       count = samples * nch;\r
+                       data += size - 1;\r
+\r
+                       ptr = vis_buffer;\r
+                       while(count--) {\r
+                               *ptr++ = data[0] ^ 0x80;\r
+                               data += size;\r
+                       }\r
+\r
+                       data = vis_buffer;\r
+                       resolution = 8;\r
+                       /* fall through */\r
+               case 16:\r
+               case 8:\r
+                       mod_.SAAddPCMData(data, nch, resolution, position);\r
+                       mod_.VSAAddPCMData(data, nch, resolution, position);\r
+       }\r
+}\r
+\r
+static DWORD WINAPI DecodeThread(void *unused)\r
+{\r
+       const unsigned channels = stream_data_.channels;\r
+       const unsigned bits_per_sample = stream_data_.bits_per_sample;\r
+       const unsigned target_bps = stream_data_.output_bits_per_sample;\r
+       const unsigned sample_rate = stream_data_.sample_rate;\r
+       const unsigned fact = channels * (target_bps/8);\r
+\r
+       while (stream_data_.is_playing)\r
+       {\r
+               /* seek needed */\r
+               if (stream_data_.seek_to != -1)\r
+               {\r
+                       const int pos = FLAC_plugin__seek(decoder_, &stream_data_);\r
+                       if (pos != -1) mod_.outMod->Flush(pos);\r
+               }\r
+               /* stream ended */\r
+               else if (stream_data_.eof)\r
+               {\r
+                       if (!mod_.outMod->IsPlaying())\r
+                       {\r
+                               PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);\r
+                               return 0;\r
+                       }\r
+                       Sleep(10);\r
+               }\r
+               /* decode */\r
+               else\r
+               {\r
+                       /* decode samples */\r
+                       int bytes = FLAC_plugin__decode(decoder_, &stream_data_, sample_buffer_);\r
+                       const int n = bytes / fact;\r
+                       /* visualization */\r
+                       do_vis(sample_buffer_, channels, target_bps, mod_.outMod->GetWrittenTime(), n);\r
+                       /* dsp */\r
+                       if (mod_.dsp_isactive())\r
+                               bytes = mod_.dsp_dosamples((short*)sample_buffer_, n, target_bps, channels, sample_rate) * fact;\r
+                       /* output */\r
+                       while (mod_.outMod->CanWrite()<bytes && stream_data_.is_playing && stream_data_.seek_to==-1)\r
+                               Sleep(20);\r
+                       if (stream_data_.is_playing && stream_data_.seek_to==-1)\r
+                               mod_.outMod->Write(sample_buffer_, bytes);\r
+                       /* show bitrate */\r
+                       if (flac_cfg.display.show_bps)\r
+                       {\r
+                               const int rate = FLAC_plugin__get_rate(mod_.outMod->GetWrittenTime(), mod_.outMod->GetOutputTime(), &stream_data_);\r
+                               if (rate) mod_.SetInfo(rate/1000, stream_data_.sample_rate/1000, stream_data_.channels, 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*\r
+ *  title formatting\r
+ */\r
+\r
+static T_CHAR *get_tag(const T_CHAR *tag, void *param)\r
+{\r
+       FLAC__StreamMetadata *tags = (FLAC__StreamMetadata*)param;\r
+       char *tagname, *p;\r
+       T_CHAR *val;\r
+\r
+       if (!tag)\r
+               return 0;\r
+       /* Vorbis comment names must be ASCII, so convert 'tag' first */\r
+       tagname = safe_malloc_add_2op_(wcslen(tag), /*+*/1);\r
+       for(p=tagname;*tag;) {\r
+               if(*tag > 0x7d) {\r
+                       free(tagname);\r
+                       return 0;\r
+               }\r
+               else\r
+                       *p++ = (char)(*tag++);\r
+       }\r
+       *p++ = '\0';\r
+       /* now get it */\r
+       val = FLAC_plugin__tags_get_tag_ucs2(tags, tagname);\r
+       free(tagname);\r
+       /* some "user friendly cheavats" */\r
+       if (!val)\r
+       {\r
+               if (!wcsicmp(tag, L"ARTIST"))\r
+               {\r
+                       val = FLAC_plugin__tags_get_tag_ucs2(tags, "PERFORMER");\r
+                       if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "COMPOSER");\r
+               }\r
+               else if (!wcsicmp(tag, L"YEAR") || !wcsicmp(tag, L"DATE"))\r
+               {\r
+                       val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_RECORDED");\r
+                       if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_PERFORMED");\r
+               }\r
+       }\r
+\r
+       return val;\r
+}\r
+\r
+static void free_tag(T_CHAR *tag, void *param)\r
+{\r
+       (void)param;\r
+       free(tag);\r
+}\r
+\r
+static void format_title(const char *filename, WCHAR *title, unsigned max_size)\r
+{\r
+       FLAC__StreamMetadata *tags;\r
+\r
+       ReadTags(filename, &tags, /*forDisplay=*/true);\r
+\r
+       tagz_format(flac_cfg.title.tag_format_w, get_tag, free_tag, tags, title, max_size);\r
+\r
+       FLAC_plugin__tags_destroy(&tags);\r
+}\r
+\r
+static void getfileinfo(char *filename, char *title, int *length_in_msec)\r
+{\r
+       FLAC__StreamMetadata streaminfo;\r
+\r
+       if (!filename || !*filename) {\r
+               filename = lastfn_;\r
+               if (length_in_msec) {\r
+                       *length_in_msec = stream_data_.length_in_msec;\r
+                       length_in_msec = 0;    /* force skip in following code */\r
+               }\r
+       }\r
+\r
+       if (!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {\r
+               if (length_in_msec)\r
+                       *length_in_msec = -1;\r
+               return;\r
+       }\r
+\r
+       if (title) {\r
+               static WCHAR buffer[400];\r
+               format_title(filename, buffer, 400);\r
+               WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, buffer, -1, title, 400, NULL, NULL);\r
+       }\r
+\r
+       if (length_in_msec) {\r
+               /* with VC++ you have to spoon feed it the casting from uint64->int64->double */\r
+               FLAC__uint64 l = (FLAC__uint64)((double)(FLAC__int64)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);\r
+               if (l > INT_MAX)\r
+                       l = INT_MAX;\r
+               *length_in_msec = (int)l;\r
+       }\r
+}\r
+\r
+/*\r
+ *  interface\r
+ */\r
+\r
+void FLAC_plugin__show_error(const char *message,...)\r
+{\r
+       char foo[512];\r
+       va_list args;\r
+       va_start(args, message);\r
+       vsprintf(foo, message, args);\r
+       va_end(args);\r
+       MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);\r
+}\r
+\r
+static void about(HWND hwndParent)\r
+{\r
+       MessageBox(hwndParent, "Winamp2 FLAC Plugin v"PLUGIN_VERSION"\nby Josh Coalson and X-Fixer\n\nuses libFLAC "VERSION"\nSee http://flac.sourceforge.net/\n", "About FLAC Plugin", MB_ICONINFORMATION);\r
+}\r
+\r
+static void config(HWND hwndParent)\r
+{\r
+       if (DoConfig(mod_.hDllInstance, hwndParent))\r
+               WriteConfig();\r
+}\r
+\r
+static int infobox(char *fn, HWND hwnd)\r
+{\r
+       DoInfoBox(mod_.hDllInstance, hwnd, fn);\r
+       return 0;\r
+}\r
+\r
+/*\r
+ *  exported stuff\r
+ */\r
+\r
+static In_Module mod_ =\r
+{\r
+       IN_VER,\r
+       "FLAC Decoder v" PLUGIN_VERSION,\r
+       0,                                    /* hMainWindow */\r
+       0,                                    /* hDllInstance */\r
+       "FLAC\0FLAC Audio File (*.FLAC)\0",\r
+       1,                                    /* is_seekable */\r
+       1,                                    /* uses output */\r
+       config,\r
+       about,\r
+       init,\r
+       quit,\r
+       getfileinfo,\r
+       infobox,\r
+       isourfile,\r
+       play,\r
+       pause,\r
+       unpause,\r
+       ispaused,\r
+       stop,\r
+\r
+       getlength,\r
+       getoutputtime,\r
+       setoutputtime,\r
+\r
+       setvolume,\r
+       setpan,\r
+\r
+       0,0,0,0,0,0,0,0,0,                    /* vis stuff */\r
+       0,0,                                  /* dsp */\r
+       eq_set,\r
+       NULL,                                 /* setinfo */\r
+       0                                     /* out_mod */\r
+};\r
+\r
+__declspec(dllexport) In_Module *winampGetInModule2()\r
+{\r
+       return &mod_;\r
+}\r
+\r
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)\r
+{\r
+       return TRUE;\r
+}\r
diff --git a/src/plugin_winamp2/in_flac.dsp b/src/plugin_winamp2/in_flac.dsp
new file mode 100644 (file)
index 0000000..8c813d4
--- /dev/null
@@ -0,0 +1,154 @@
+# Microsoft Developer Studio Project File - Name="in_flac" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=in_flac - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "in_flac.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "in_flac.mak" CFG="in_flac - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "in_flac - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "in_flac - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "$/Studio/in_flac"\r
+# PROP Scc_LocalPath "."\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "in_flac - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /Gf /Gy /I "include" /I ".." /I "..\..\include" /D "NDEBUG" /D VERSION=\"1.2.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TAGZ_UNICODE" /YX /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+# ADD LINK32 plugin_common_static.lib grabbag_static.lib libFLAC_static.lib replaygain_analysis_static.lib replaygain_synthesis_static.lib kernel32.lib user32.lib /nologo /dll /machine:I386 /out:"../../obj/release/bin/in_flac.dll" /libpath:"../../obj/release/lib" ..\..\obj\release\lib\ogg_static.lib /opt:nowin98\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF  "$(CFG)" == "in_flac - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I ".." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "REAL_STDIO" /D VERSION=\"1.2.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TAGZ_UNICODE" /YX /FD /GZ /c\r
+# SUBTRACT CPP /WX\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 plugin_common_static.lib grabbag_static.lib libFLAC_static.lib replaygain_analysis_static.lib replaygain_synthesis_static.lib kernel32.lib user32.lib /nologo /dll /debug /machine:I386 /out:"../../obj/debug/bin/in_flac.dll" /pdbtype:sept /libpath:"../../obj/debug/lib" ..\..\obj\release\lib\ogg_static.lib\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "in_flac - Win32 Release"\r
+# Name "in_flac - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Group "Winamp2 SDK"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\winamp2\in2.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\include\winamp2\out.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\configure.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\configure.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\in_flac.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\infobox.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\infobox.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\playback.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\playback.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\resource.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\resource.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\tagz.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\tagz.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/plugin_winamp2/in_flac.vcproj b/src/plugin_winamp2/in_flac.vcproj
new file mode 100644 (file)
index 0000000..d842707
--- /dev/null
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="in_flac"\r
+       ProjectGUID="{4cefbc82-c215-11db-8314-0800200c9a66}"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;IN_FLAC_EXPORTS;FLAC__NO_DLL;VERSION=\&quot;1.2.0\&quot;;TAGZ_UNICODE;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include&quot;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib user32.lib"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Lib"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_dynamic"\r
+                       ConfigurationType="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_FLAC_EXPORTS;FLAC__NO_DLL;VERSION=\&quot;1.2.0\&quot;;TAGZ_UNICODE"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include&quot;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib user32.lib"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Lib"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\configure.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\winamp2\in2.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\infobox.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\winamp2\out.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\playback.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\resource.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\tagz.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\resource.rc"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\configure.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\in_flac.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\infobox.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\playback.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\tagz.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/plugin_winamp2/include/Makefile.am b/src/plugin_winamp2/include/Makefile.am
new file mode 100644 (file)
index 0000000..ea96623
--- /dev/null
@@ -0,0 +1,18 @@
+#  in_flac - Winamp2 FLAC input plugin
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+SUBDIRS = winamp2
diff --git a/src/plugin_winamp2/include/winamp2/Makefile.am b/src/plugin_winamp2/include/winamp2/Makefile.am
new file mode 100644 (file)
index 0000000..8153ed8
--- /dev/null
@@ -0,0 +1,20 @@
+#  in_flac - Winamp2 FLAC input plugin
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+EXTRA_DIST = \
+       in2.h \
+       out.h
diff --git a/src/plugin_winamp2/include/winamp2/in2.h b/src/plugin_winamp2/include/winamp2/in2.h
new file mode 100644 (file)
index 0000000..46e22f0
--- /dev/null
@@ -0,0 +1,107 @@
+/* Standard Winamp input-plugin header
+ */
+
+#include "out.h"
+
+/* post this to the main window at end of file (after playback as stopped) */\r
+#define WM_WA_MPEG_EOF          (WM_USER + 2)\r
+\r
+// note: exported symbol is now winampGetInModule2.
+
+#define IN_VER 0x100
+
+typedef struct
+{
+       int version;                            // module type (IN_VER)
+       char *description;                      // description of module, with version string
+
+       HWND hMainWindow;                       // winamp's main window (filled in by winamp)
+       HINSTANCE hDllInstance;         // DLL instance handle (Also filled in by winamp)
+
+       char *FileExtensions;           // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
+                                                               // May be altered from Config, so the user can select what they want
+
+       int is_seekable;                        // is this stream seekable?
+       int UsesOutputPlug;                     // does this plug-in use the output plug-ins? (musn't ever change, ever :)
+
+       void (*Config)(HWND hwndParent); // configuration dialog
+       void (*About)(HWND hwndParent);  // about dialog
+
+       void (*Init)();                         // called at program init
+       void (*Quit)();                         // called at program quit
+
+       void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
+       int (*InfoBox)(char *file, HWND hwndParent);
+
+       int (*IsOurFile)(char *fn);     // called before extension checks, to allow detection of mms://, etc
+       // playback stuff
+       int (*Play)(char *fn);          // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
+       void (*Pause)();                        // pause stream
+       void (*UnPause)();                      // unpause stream
+       int (*IsPaused)();                      // ispaused? return 1 if paused, 0 if not
+       void (*Stop)();                         // stop (unload) stream
+
+       // time stuff
+       int (*GetLength)();                     // get length in ms
+       int (*GetOutputTime)();         // returns current output time in ms. (usually returns outMod->GetOutputTime()
+       void (*SetOutputTime)(int time_in_ms);  // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
+
+       // volume stuff
+       void (*SetVolume)(int volume);  // from 0 to 255.. usually just call outMod->SetVolume
+       void (*SetPan)(int pan);        // from -127 to 127.. usually just call outMod->SetPan
+
+       // in-window builtin vis stuff
+
+       void (*SAVSAInit)(int maxlatency_in_ms, int srate);             // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
+       // call after opening audio device with max latency in ms and samplerate
+       void (*SAVSADeInit)();  // call in Stop()
+
+
+       // simple vis supplying mode
+       void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
+                                                                                       // sets the spec data directly from PCM data
+                                                                                       // quick and easy way to get vis working :)
+                                                                                       // needs at least 576 samples :)
+
+       // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
+       int (*SAGetMode)();             // gets csa (the current type (4=ws,2=osc,1=spec))
+                                                       // use when calling SAAdd()
+       void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
+
+
+       // vis stuff (plug-in)
+       // simple vis supplying mode
+       void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
+                                                                                       // quick and easy way to get vis working :)
+                                                                                       // needs at least 576 samples :)
+
+       // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
+       int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
+       void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
+
+
+       // call this in Play() to tell the vis plug-ins the current output params.
+       void (*VSASetInfo)(int nch, int srate);
+
+
+       // dsp plug-in processing:
+       // (filled in by winamp, called by input plug)
+
+       // returns 1 if active (which means that the number of samples returned by dsp_dosamples
+       // could be greater than went in.. Use it to estimate if you'll have enough room in the
+       // output buffer
+       int (*dsp_isactive)();
+
+       // returns number of samples to output. This can be as much as twice numsamples.
+       // be sure to allocate enough buffer for samples, then.
+       int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
+
+
+       // eq stuff
+       void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
+
+       // info setting (filled in by winamp)
+       void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
+
+       Out_Module *outMod; // filled in by winamp, optionally used :)
+} In_Module;
diff --git a/src/plugin_winamp2/include/winamp2/out.h b/src/plugin_winamp2/include/winamp2/out.h
new file mode 100644 (file)
index 0000000..e8ad412
--- /dev/null
@@ -0,0 +1,55 @@
+/* Standard Winamp output-plugin header
+ */
+
+#define OUT_VER 0x10
+
+typedef struct
+{
+       int version;                            // module version (OUT_VER)
+       char *description;                      // description of module, with version string
+       int id;                                         // module id. each input module gets its own. non-nullsoft modules should
+                                                               // be >= 65536.
+
+       HWND hMainWindow;                       // winamp's main window (filled in by winamp)
+       HINSTANCE hDllInstance;         // DLL instance handle (filled in by winamp)
+
+       void (*Config)(HWND hwndParent); // configuration dialog
+       void (*About)(HWND hwndParent);  // about dialog
+
+       void (*Init)();                         // called when loaded
+       void (*Quit)();                         // called when unloaded
+
+       int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
+                                       // returns >=0 on success, <0 on failure
+                                       // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
+                                       //    ... so don't expect the max latency returned to be what you asked for.
+                                       // returns max latency in ms (0 for diskwriters, etc)
+                                       // bufferlenms and prebufferms must be in ms. 0 to use defaults.
+                                       // prebufferms must be <= bufferlenms
+
+       void (*Close)();        // close the ol' output device.
+
+       int (*Write)(char *buf, int len);
+                                       // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
+                                       // 1 returns not able to write (yet). Non-blocking, always.
+
+       int (*CanWrite)();      // returns number of bytes possible to write at a given time.
+                                               // Never will decrease unless you call Write (or Close, heh)
+
+       int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
+                                               // written (i.e. closing while IsPlaying() returns 1 would truncate the song
+
+       int (*Pause)(int pause); // returns previous pause state
+
+       void (*SetVolume)(int volume); // volume is 0-255
+       void (*SetPan)(int pan); // pan is -128 to 128
+
+       void (*Flush)(int t);   // flushes buffers and restarts output at time t (in ms)
+                                                       // (used for seeking)
+
+       int (*GetOutputTime)(); // returns played time in MS
+       int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
+
+} Out_Module;
+
+
diff --git a/src/plugin_winamp2/infobox.c b/src/plugin_winamp2/infobox.c
new file mode 100644 (file)
index 0000000..9418eeb
--- /dev/null
@@ -0,0 +1,459 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include "FLAC/all.h"\r
+#include "share/alloc.h"\r
+#include "plugin_common/all.h"\r
+#include "infobox.h"\r
+#include "configure.h"\r
+#include "resource.h"\r
+\r
+\r
+typedef struct\r
+{\r
+       char filename[MAX_PATH];\r
+       FLAC__StreamMetadata *tags;\r
+} LOCALDATA;\r
+\r
+static char buffer[8192];\r
+static char *genres = NULL;\r
+static DWORD genresSize = 0, genresCount = 0;\r
+static BOOL genresChanged = FALSE, isNT;\r
+\r
+static const char infoTitle[] = "FLAC File Info";\r
+\r
+/*\r
+ *  Genres\r
+ */\r
+\r
+/* TODO: write genres in utf-8 ? */\r
+\r
+static __inline int GetGenresFileName(char *buffer, int size)\r
+{\r
+       char *c;\r
+\r
+       if (!GetModuleFileName(NULL, buffer, size))\r
+               return 0;\r
+       c = strrchr(buffer, '\\');\r
+       if (!c) return 0;\r
+       strcpy(c+1, "genres.txt");\r
+\r
+       return 1;\r
+}\r
+\r
+static void LoadGenres()\r
+{\r
+       HANDLE hFile;\r
+       DWORD  spam;\r
+       char  *c;\r
+\r
+       FLAC__ASSERT(0 != genres);\r
+\r
+       if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
+       /* load file */\r
+       hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+       if (hFile == INVALID_HANDLE_VALUE) return;\r
+       genresSize = GetFileSize(hFile, 0);\r
+       if (genresSize && (genres = (char*)safe_malloc_add_2op_(genresSize, /*+*/2)))\r
+       {\r
+               if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)\r
+               {\r
+                       free(genres);\r
+                       genres = NULL;\r
+               }\r
+               else\r
+               {\r
+                       genres[genresSize] = 0;\r
+                       genres[genresSize+1] = 0;\r
+                       /* replace newlines */\r
+                       genresChanged = FALSE;\r
+                       genresCount = 1;\r
+\r
+                       for (c=genres; *c; c++)\r
+                       {\r
+                               if (*c == 10)\r
+                               {\r
+                                       *c = 0;\r
+                                       if (*(c+1))\r
+                                               genresCount++;\r
+                                       else genresSize--;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       CloseHandle(hFile);\r
+}\r
+\r
+static void SaveGenres(HWND hlist)\r
+{\r
+       HANDLE hFile;\r
+       DWORD  spam;\r
+       int i, count, len;\r
+\r
+       if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
+       /* write file */\r
+       hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
+       if (hFile == INVALID_HANDLE_VALUE) return;\r
+\r
+       count = SendMessage(hlist, CB_GETCOUNT, 0, 0);\r
+       for (i=0; i<count; i++)\r
+       {\r
+               SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);\r
+               len = strlen(buffer);\r
+               if (i != count-1)\r
+               {\r
+                       buffer[len] = 10;\r
+                       len++;\r
+               }\r
+               WriteFile(hFile, buffer, len, &spam, NULL);\r
+       }\r
+\r
+       CloseHandle(hFile);\r
+}\r
+\r
+static void AddGenre(HWND hwnd, const char *genre)\r
+{\r
+       HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
+\r
+       if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)\r
+       {\r
+               genresChanged = TRUE;\r
+               SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);\r
+       }\r
+}\r
+\r
+static void InitGenres(HWND hwnd)\r
+{\r
+       HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
+       char *c;\r
+\r
+       /* set text length limit to 64 chars */\r
+       SendMessage(hgen, CB_LIMITTEXT, 64, 0);\r
+       /* try to load genres */\r
+       if (!genres)\r
+               LoadGenres(hgen);\r
+       /* add the to list */\r
+       if (genres)\r
+       {\r
+               SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);\r
+\r
+               for (c = genres; *c; c += strlen(c)+1)\r
+                       SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);\r
+       }\r
+}\r
+\r
+static void DeinitGenres(HWND hwnd, BOOL final)\r
+{\r
+       if (genresChanged && hwnd)\r
+       {\r
+               SaveGenres(GetDlgItem(hwnd, IDC_GENRE));\r
+               genresChanged = FALSE;\r
+               final = TRUE;\r
+       }\r
+       if (final)\r
+       {\r
+               free(genres);\r
+               genres = 0;\r
+       }\r
+}\r
+\r
+static wchar_t *AnsiToWide(const char *src)\r
+{\r
+       int len;\r
+       wchar_t *dest;\r
+\r
+       FLAC__ASSERT(0 != src);\r
+\r
+       len = strlen(src) + 1;\r
+       /* copy */\r
+       dest = (wchar_t*)safe_malloc_mul_2op_(len, /*times*/sizeof(wchar_t));\r
+       if (dest) mbstowcs(dest, src, len);\r
+       return dest;\r
+}\r
+\r
+/*\r
+ *  Infobox helpers\r
+ */\r
+\r
+#define SetText(x,y)            ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \\r
+                                WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL); \\r
+                                if(ucs2) free(ucs2); \\r
+                                SetDlgItemText(hwnd, x, buffer)\r
+\r
+#define GetText(x,y)            GetDlgItemText(hwnd, x, buffer, sizeof(buffer));                        \\r
+                                if (*buffer) { ucs2 = AnsiToWide(buffer); FLAC_plugin__tags_set_tag_ucs2(data->tags, y, ucs2, /*replace_all=*/false); free(ucs2); } \\r
+                                else FLAC_plugin__tags_delete_tag(data->tags, y)\r
+\r
+#define SetTextW(x,y)           ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \\r
+                                SetDlgItemTextW(hwnd, x, ucs2); \\r
+                                free(ucs2)\r
+\r
+#define GetTextW(x,y)           GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2);                     \\r
+                                if (*(WCHAR*)buffer) FLAC_plugin__tags_set_tag_ucs2(data->tags, y, (WCHAR*)buffer, /*replace_all=*/false); \\r
+                                else FLAC_plugin__tags_delete_tag(data->tags, y)\r
+\r
+\r
+static BOOL InitInfoboxInfo(HWND hwnd, const char *file)\r
+{\r
+       LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));\r
+       wchar_t *ucs2;\r
+       FLAC__StreamMetadata streaminfo;\r
+       DWORD    length, bps, ratio, rg;\r
+       LONGLONG filesize;\r
+\r
+       SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);\r
+       /* file name */\r
+       strncpy(data->filename, file, sizeof(data->filename));\r
+       SetDlgItemText(hwnd, IDC_NAME, file);\r
+       /* stream data and vorbis comment */\r
+       filesize = FileSize(file);\r
+       if (!filesize) return FALSE;\r
+       if (!FLAC__metadata_get_streaminfo(file, &streaminfo))\r
+               return FALSE;\r
+       ReadTags(file, &data->tags, false);\r
+\r
+       length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);\r
+       bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));\r
+       ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);\r
+       rg  = FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_TRACK_GAIN") ? 1 : 0;\r
+       rg |= FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;\r
+\r
+       sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"\r
+                       "File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"\r
+                       "ReplayGain: %s\n",\r
+           streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,\r
+           streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,\r
+           length/60, length%60, bps, ratio/10, ratio%10,\r
+           rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");\r
+\r
+       SetDlgItemText(hwnd, IDC_INFO, buffer);\r
+       /* tag */\r
+       if (isNT)\r
+       {\r
+               SetTextW(IDC_TITLE,   "TITLE");\r
+               SetTextW(IDC_ARTIST,  "ARTIST");\r
+               SetTextW(IDC_ALBUM,   "ALBUM");\r
+               SetTextW(IDC_COMMENT, "COMMENT");\r
+               SetTextW(IDC_YEAR,    "DATE");\r
+               SetTextW(IDC_TRACK,   "TRACKNUMBER");\r
+               SetTextW(IDC_GENRE,   "GENRE");\r
+       }\r
+       else\r
+       {\r
+               SetText(IDC_TITLE,   "TITLE");\r
+               SetText(IDC_ARTIST,  "ARTIST");\r
+               SetText(IDC_ALBUM,   "ALBUM");\r
+               SetText(IDC_COMMENT, "COMMENT");\r
+               SetText(IDC_YEAR,    "DATE");\r
+               SetText(IDC_TRACK,   "TRACKNUMBER");\r
+               SetText(IDC_GENRE,   "GENRE");\r
+       }\r
+\r
+       return TRUE;\r
+}\r
+\r
+static void __inline SetTag(HWND hwnd, const char *filename, FLAC__StreamMetadata *tags)\r
+{\r
+       strcpy(buffer, infoTitle);\r
+\r
+       if (FLAC_plugin__tags_set(filename, tags))\r
+               strcat(buffer, " [Updated]");\r
+       else strcat(buffer, " [Failed]");\r
+\r
+       SetWindowText(hwnd, buffer);\r
+}\r
+\r
+static void UpdateTag(HWND hwnd)\r
+{\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       wchar_t *ucs2;\r
+\r
+       /* get fields */\r
+       if (isNT)\r
+       {\r
+               GetTextW(IDC_TITLE,   "TITLE");\r
+               GetTextW(IDC_ARTIST,  "ARTIST");\r
+               GetTextW(IDC_ALBUM,   "ALBUM");\r
+               GetTextW(IDC_COMMENT, "COMMENT");\r
+               GetTextW(IDC_YEAR,    "DATE");\r
+               GetTextW(IDC_TRACK,   "TRACKNUMBER");\r
+               GetTextW(IDC_GENRE,   "GENRE");\r
+\r
+               ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, "GENRE");\r
+               WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL);\r
+               free(ucs2);\r
+       }\r
+       else\r
+       {\r
+               GetText(IDC_TITLE,   "TITLE");\r
+               GetText(IDC_ARTIST,  "ARTIST");\r
+               GetText(IDC_ALBUM,   "ALBUM");\r
+               GetText(IDC_COMMENT, "COMMENT");\r
+               GetText(IDC_YEAR,    "DATE");\r
+               GetText(IDC_TRACK,   "TRACKNUMBER");\r
+               GetText(IDC_GENRE,   "GENRE");\r
+       }\r
+\r
+       /* update genres list (buffer should contain genre) */\r
+       if (buffer[0]) AddGenre(hwnd, buffer);\r
+\r
+       /* write tag */\r
+       SetTag(hwnd, data->filename, data->tags);\r
+}\r
+\r
+static void RemoveTag(HWND hwnd)\r
+{\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       FLAC_plugin__tags_delete_all(data->tags);\r
+\r
+       SetDlgItemText(hwnd, IDC_TITLE,   "");\r
+       SetDlgItemText(hwnd, IDC_ARTIST,  "");\r
+       SetDlgItemText(hwnd, IDC_ALBUM,   "");\r
+       SetDlgItemText(hwnd, IDC_COMMENT, "");\r
+       SetDlgItemText(hwnd, IDC_YEAR,    "");\r
+       SetDlgItemText(hwnd, IDC_TRACK,   "");\r
+       SetDlgItemText(hwnd, IDC_GENRE,   "");\r
+\r
+       SetTag(hwnd, data->filename, data->tags);\r
+}\r
+\r
+\r
+static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msg)\r
+       {\r
+       /* init */\r
+       case WM_INITDIALOG:\r
+               SetWindowText(hwnd, infoTitle);\r
+               InitGenres(hwnd);\r
+               /* init fields */\r
+               if (!InitInfoboxInfo(hwnd, (const char*)lParam))\r
+                       PostMessage(hwnd, WM_CLOSE, 0, 0);\r
+               return TRUE;\r
+       /* destroy */\r
+       case WM_DESTROY:\r
+               {\r
+                       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+                       FLAC_plugin__tags_destroy(&data->tags);\r
+                       LocalFree(data);\r
+                       DeinitGenres(hwnd, FALSE);\r
+               }\r
+               break;\r
+       /* commands */\r
+       case WM_COMMAND:\r
+               switch (LOWORD(wParam))\r
+               {\r
+               /* ok/cancel */\r
+               case IDOK:\r
+               case IDCANCEL:\r
+                       EndDialog(hwnd, LOWORD(wParam));\r
+                       return TRUE;\r
+               /* save */\r
+               case IDC_UPDATE:\r
+                       UpdateTag(hwnd);\r
+                       break;\r
+               /* remove */\r
+               case IDC_REMOVE:\r
+                       RemoveTag(hwnd);\r
+                       break;\r
+               }\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*\r
+ *  Helpers\r
+ */\r
+\r
+ULONGLONG FileSize(const char *fileName)\r
+{\r
+       LARGE_INTEGER res;\r
+       HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+\r
+       if (hFile == INVALID_HANDLE_VALUE) return 0;\r
+       res.LowPart = GetFileSize(hFile, &res.HighPart);\r
+       CloseHandle(hFile);\r
+       return res.QuadPart;\r
+}\r
+\r
+static __inline char *GetFileName(const char *fullname)\r
+{\r
+       const char *c = fullname + strlen(fullname) - 1;\r
+\r
+       while (c > fullname)\r
+       {\r
+               if (*c=='\\' || *c=='/')\r
+               {\r
+                       c++;\r
+                       break;\r
+               }\r
+               c--;\r
+       }\r
+\r
+       return (char*)c;\r
+}\r
+\r
+void ReadTags(const char *fileName, FLAC__StreamMetadata **tags, BOOL forDisplay)\r
+{\r
+       if(FLAC_plugin__tags_get(fileName, tags)) {\r
+\r
+               /* add file name */\r
+               if (forDisplay)\r
+               {\r
+                       char *c;\r
+                       wchar_t *ucs2;\r
+                       ucs2 = AnsiToWide(fileName);\r
+                       FLAC_plugin__tags_set_tag_ucs2(*tags, "filepath", ucs2, /*replace_all=*/true);\r
+                       free(ucs2);\r
+\r
+                       strcpy(buffer, GetFileName(fileName));\r
+                       if (c = strrchr(buffer, '.')) *c = 0;\r
+                       ucs2 = AnsiToWide(buffer);\r
+                       FLAC_plugin__tags_set_tag_ucs2(*tags, "filename", ucs2, /*replace_all=*/true);\r
+                       free(ucs2);\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+ *  Front-end\r
+ */\r
+\r
+void InitInfobox()\r
+{\r
+       isNT = !(GetVersion() & 0x80000000);\r
+}\r
+\r
+void DeinitInfobox()\r
+{\r
+       DeinitGenres(NULL, true);\r
+}\r
+\r
+void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)\r
+{\r
+       DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);\r
+}\r
diff --git a/src/plugin_winamp2/infobox.h b/src/plugin_winamp2/infobox.h
new file mode 100644 (file)
index 0000000..9748c2d
--- /dev/null
@@ -0,0 +1,28 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+/*\r
+ *  prototypes\r
+ */\r
+\r
+ULONGLONG FileSize(const char *fileName);\r
+void ReadTags(const char *fileName, FLAC__StreamMetadata **tags, BOOL forDisplay);\r
+\r
+void InitInfobox();\r
+void DeinitInfobox();\r
+void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename);\r
diff --git a/src/plugin_winamp2/playback.c b/src/plugin_winamp2/playback.c
new file mode 100644 (file)
index 0000000..cdadaa5
--- /dev/null
@@ -0,0 +1,307 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif\r
+\r
+#include <limits.h> /* for INT_MAX */\r
+#include <stdlib.h>\r
+#include <string.h> /* for memmove() */\r
+#include "playback.h"\r
+#include "share/grabbag.h"\r
+\r
+\r
+static FLAC__int32 reservoir_[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS][FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/];\r
+static FLAC__int32 *reservoir__[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS] = { reservoir_[0], reservoir_[1] }; /*@@@ kind of a hard-coded hack */\r
+static unsigned wide_samples_in_reservoir_;\r
+static output_config_t cfg;     /* local copy */\r
+\r
+static unsigned bh_index_last_w, bh_index_last_o, written_time_last;\r
+static FLAC__int64 decode_position, decode_position_last;\r
+\r
+/*\r
+ *  callbacks\r
+ */\r
+\r
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)\r
+{\r
+       stream_data_struct *stream_data = (stream_data_struct*)client_data;\r
+       const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize;\r
+       unsigned channel;\r
+\r
+       (void)decoder;\r
+\r
+       if (stream_data->abort_flag)\r
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;\r
+\r
+       for (channel = 0; channel < channels; channel++)\r
+               memcpy(&reservoir_[channel][wide_samples_in_reservoir_], buffer[channel], sizeof(buffer[0][0]) * wide_samples);\r
+\r
+       wide_samples_in_reservoir_ += wide_samples;\r
+\r
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;\r
+}\r
+\r
+static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)\r
+{\r
+       stream_data_struct *stream_data = (stream_data_struct*)client_data;\r
+       (void)decoder;\r
+\r
+       if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)\r
+       {\r
+               stream_data->total_samples = metadata->data.stream_info.total_samples;\r
+               stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample;\r
+               stream_data->channels = metadata->data.stream_info.channels;\r
+               stream_data->sample_rate = metadata->data.stream_info.sample_rate;\r
+\r
+               if (stream_data->bits_per_sample!=8 && stream_data->bits_per_sample!=16 && stream_data->bits_per_sample!=24)\r
+               {\r
+                       FLAC_plugin__show_error("This plugin can only handle 8/16/24-bit samples.");\r
+                       stream_data->abort_flag = true;\r
+                       return;\r
+               }\r
+\r
+               {\r
+                       /* with VC++ you have to spoon feed it the casting from uint64->int64->double */\r
+                       FLAC__uint64 l = (FLAC__uint64)((double)(FLAC__int64)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5);\r
+                       if (l > INT_MAX)\r
+                               l = INT_MAX;\r
+                       stream_data->length_in_msec = (int)l;\r
+               }\r
+       }\r
+       else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)\r
+       {\r
+               double reference, gain, peak;\r
+               if (grabbag__replaygain_load_from_vorbiscomment(metadata, cfg.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak))\r
+               {\r
+                       stream_data->has_replaygain = true;\r
+                       stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)cfg.replaygain.preamp, !cfg.replaygain.hard_limit);\r
+               }\r
+       }\r
+}\r
+\r
+static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
+{\r
+       stream_data_struct *stream_data = (stream_data_struct*)client_data;\r
+       (void)decoder;\r
+\r
+       if (cfg.misc.stop_err || status!=FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)\r
+               stream_data->abort_flag = true;\r
+}\r
+\r
+/*\r
+ *  init/delete\r
+ */\r
+\r
+FLAC__bool FLAC_plugin__decoder_init(FLAC__StreamDecoder *decoder, const char *filename, FLAC__int64 filesize, stream_data_struct *stream_data, output_config_t *config)\r
+{\r
+       FLAC__StreamDecoderInitStatus init_status;\r
+\r
+       FLAC__ASSERT(decoder);\r
+       FLAC_plugin__decoder_finish(decoder);\r
+       /* init decoder */\r
+       FLAC__stream_decoder_set_md5_checking(decoder, false);\r
+       FLAC__stream_decoder_set_metadata_ignore_all(decoder);\r
+       FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);\r
+       FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);\r
+\r
+       if ((init_status = FLAC__stream_decoder_init_file(decoder, filename, write_callback, metadata_callback, error_callback, /*client_data=*/stream_data)) != FLAC__STREAM_DECODER_INIT_STATUS_OK)\r
+       {\r
+               FLAC_plugin__show_error("Error while initializing decoder (%s [%s]).", FLAC__StreamDecoderInitStatusString[init_status], FLAC__stream_decoder_get_resolved_state_string(decoder));\r
+               return false;\r
+       }\r
+       /* process */\r
+       cfg = *config;\r
+       wide_samples_in_reservoir_ = 0;\r
+       stream_data->is_playing = false;\r
+       stream_data->abort_flag = false;\r
+       stream_data->has_replaygain = false;\r
+\r
+       if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder))\r
+       {\r
+               FLAC_plugin__show_error("Error while processing metadata (%s).", FLAC__stream_decoder_get_resolved_state_string(decoder));\r
+               return false;\r
+       }\r
+       /* check results */\r
+       if (stream_data->abort_flag) return false;                /* metadata callback already popped up the error dialog */\r
+       /* init replaygain */\r
+       stream_data->output_bits_per_sample = stream_data->has_replaygain && cfg.replaygain.enable ?\r
+               cfg.resolution.replaygain.bps_out :\r
+               cfg.resolution.normal.dither_24_to_16 ? min(stream_data->bits_per_sample, 16) : stream_data->bits_per_sample;\r
+\r
+       if (stream_data->has_replaygain && cfg.replaygain.enable && cfg.resolution.replaygain.dither)\r
+               FLAC__replaygain_synthesis__init_dither_context(&stream_data->dither_context, stream_data->bits_per_sample, cfg.resolution.replaygain.noise_shaping);\r
+       /* more inits */\r
+       stream_data->eof = false;\r
+       stream_data->seek_to = -1;\r
+       stream_data->is_playing = true;\r
+       stream_data->average_bps = (unsigned)(filesize / (125.*(double)(FLAC__int64)stream_data->total_samples/(double)stream_data->sample_rate));\r
+       \r
+       bh_index_last_w = 0;\r
+       bh_index_last_o = BITRATE_HIST_SIZE;\r
+       decode_position = 0;\r
+       decode_position_last = 0;\r
+       written_time_last = 0;\r
+\r
+       return true;\r
+}\r
+\r
+void FLAC_plugin__decoder_finish(FLAC__StreamDecoder *decoder)\r
+{\r
+       if (decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED)\r
+               (void)FLAC__stream_decoder_finish(decoder);\r
+}\r
+\r
+void FLAC_plugin__decoder_delete(FLAC__StreamDecoder *decoder)\r
+{\r
+       if (decoder)\r
+       {\r
+               FLAC_plugin__decoder_finish(decoder);\r
+               FLAC__stream_decoder_delete(decoder);\r
+       }\r
+}\r
+\r
+/*\r
+ *  decode\r
+ */\r
+\r
+int FLAC_plugin__seek(FLAC__StreamDecoder *decoder, stream_data_struct *stream_data)\r
+{\r
+       int pos;\r
+       FLAC__uint64 target_sample = stream_data->total_samples * stream_data->seek_to / stream_data->length_in_msec;\r
+\r
+       if (stream_data->total_samples > 0 && target_sample >= stream_data->total_samples && target_sample > 0)\r
+               target_sample = stream_data->total_samples - 1;\r
+\r
+       /* even if the seek fails we have to reset these so that we don't repeat the seek */\r
+       stream_data->seek_to = -1;\r
+       stream_data->eof = false;\r
+       wide_samples_in_reservoir_ = 0;\r
+       pos = (int)(target_sample*1000 / stream_data->sample_rate);\r
+\r
+       if (!FLAC__stream_decoder_seek_absolute(decoder, target_sample)) {\r
+               if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEEK_ERROR)\r
+                       FLAC__stream_decoder_flush(decoder);\r
+               pos = -1;\r
+       }\r
+\r
+       bh_index_last_o = bh_index_last_w = (pos/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;\r
+       if (!FLAC__stream_decoder_get_decode_position(decoder, &decode_position))\r
+               decode_position = 0;\r
+\r
+       return pos;\r
+}\r
+\r
+unsigned FLAC_plugin__decode(FLAC__StreamDecoder *decoder, stream_data_struct *stream_data, char *sample_buffer)\r
+{\r
+       /* fill reservoir */\r
+       while (wide_samples_in_reservoir_ < SAMPLES_PER_WRITE)\r
+       {\r
+               if (FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)\r
+               {\r
+                       stream_data->eof = true;\r
+                       break;\r
+               }\r
+               else if (!FLAC__stream_decoder_process_single(decoder))\r
+               {\r
+                       FLAC_plugin__show_error("Error while processing frame (%s).", FLAC__stream_decoder_get_resolved_state_string(decoder));\r
+                       stream_data->eof = true;\r
+                       break;\r
+               }\r
+               if (!FLAC__stream_decoder_get_decode_position(decoder, &decode_position))\r
+                       decode_position = 0;\r
+       }\r
+       /* output samples */\r
+       if (wide_samples_in_reservoir_ > 0)\r
+       {\r
+               const unsigned n = min(wide_samples_in_reservoir_, SAMPLES_PER_WRITE);\r
+               const unsigned channels = stream_data->channels;\r
+               unsigned i;\r
+               int bytes;\r
+\r
+               if (cfg.replaygain.enable && stream_data->has_replaygain)\r
+               {\r
+                       bytes = FLAC__replaygain_synthesis__apply_gain(\r
+                               sample_buffer,\r
+                               true, /* little_endian_data_out */\r
+                               stream_data->output_bits_per_sample == 8, /* unsigned_data_out */\r
+                               reservoir__,\r
+                               n,\r
+                               channels,\r
+                               stream_data->bits_per_sample,\r
+                               stream_data->output_bits_per_sample,\r
+                               stream_data->replay_scale,\r
+                               cfg.replaygain.hard_limit,\r
+                               cfg.resolution.replaygain.dither,\r
+                               &stream_data->dither_context\r
+                       );\r
+               }\r
+               else\r
+               {\r
+                       bytes = FLAC__plugin_common__pack_pcm_signed_little_endian(\r
+                               sample_buffer,\r
+                               reservoir__,\r
+                               n,\r
+                               channels,\r
+                               stream_data->bits_per_sample,\r
+                               stream_data->output_bits_per_sample\r
+                       );\r
+               }\r
+\r
+               wide_samples_in_reservoir_ -= n;\r
+               for (i = 0; i < channels; i++)\r
+                       memmove(&reservoir_[i][0], &reservoir_[i][n], sizeof(reservoir_[0][0]) * wide_samples_in_reservoir_);\r
+\r
+               return bytes;\r
+       }\r
+       else\r
+       {\r
+               stream_data->eof = true;\r
+               return 0;\r
+       }\r
+}\r
+\r
+int FLAC_plugin__get_rate(unsigned written_time, unsigned output_time, stream_data_struct *stream_data)\r
+{\r
+       static int bitrate_history_[BITRATE_HIST_SIZE];\r
+       unsigned bh_index_w = (written_time/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;\r
+       unsigned bh_index_o = (output_time/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;\r
+\r
+       /* written bitrate */\r
+       if (bh_index_w != bh_index_last_w)\r
+       {\r
+               bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE-1)%BITRATE_HIST_SIZE] =\r
+                       decode_position>decode_position_last && written_time > written_time_last ?\r
+                       (unsigned)(8000*(decode_position - decode_position_last)/(written_time - written_time_last)) :\r
+                       stream_data->average_bps;\r
+\r
+               bh_index_last_w = bh_index_w;\r
+               written_time_last = written_time;\r
+               decode_position_last = decode_position;\r
+       }\r
+\r
+       /* output bitrate */\r
+       if (bh_index_o!=bh_index_last_o && bh_index_o!=bh_index_last_w)\r
+       {\r
+               bh_index_last_o = bh_index_o;\r
+               return bitrate_history_[bh_index_o];\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/src/plugin_winamp2/playback.h b/src/plugin_winamp2/playback.h
new file mode 100644 (file)
index 0000000..4648adc
--- /dev/null
@@ -0,0 +1,92 @@
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ */\r
+\r
+#include "FLAC/all.h"\r
+#include "share/replaygain_synthesis.h"\r
+#include "plugin_common/all.h"\r
+\r
+/*\r
+ *  constants\r
+ */\r
+\r
+#define SAMPLES_PER_WRITE           576\r
+\r
+#define BITRATE_HIST_SEGMENT_MSEC   500\r
+#define BITRATE_HIST_SIZE           64\r
+\r
+/*\r
+ *  common structures\r
+ */\r
+\r
+typedef struct {\r
+       volatile FLAC__bool is_playing;\r
+       volatile FLAC__bool abort_flag;\r
+       volatile FLAC__bool eof;\r
+       volatile int seek_to;\r
+       FLAC__uint64 total_samples;\r
+       unsigned bits_per_sample;\r
+       unsigned output_bits_per_sample;\r
+       unsigned channels;\r
+       unsigned sample_rate;\r
+       int length_in_msec; /* int (instead of FLAC__uint64) only because that's what Winamp uses; seeking won't work right if this maxes out */\r
+       unsigned average_bps;\r
+       FLAC__bool has_replaygain;\r
+       double replay_scale;\r
+       DitherContext dither_context;\r
+} stream_data_struct;\r
+\r
+\r
+typedef struct {\r
+       struct {\r
+               FLAC__bool enable;\r
+               FLAC__bool album_mode;\r
+               int  preamp;\r
+               FLAC__bool hard_limit;\r
+       } replaygain;\r
+       struct {\r
+               struct {\r
+                       FLAC__bool dither_24_to_16;\r
+               } normal;\r
+               struct {\r
+                       FLAC__bool dither;\r
+                       int  noise_shaping; /* value must be one of NoiseShaping enum, see plugin_common/replaygain_synthesis.h */\r
+                       int  bps_out;\r
+               } replaygain;\r
+       } resolution;\r
+       struct {\r
+               FLAC__bool stop_err;\r
+       } misc;\r
+} output_config_t;\r
+\r
+/*\r
+ *  protopytes\r
+ */\r
+\r
+FLAC__bool FLAC_plugin__decoder_init(FLAC__StreamDecoder *decoder, const char *filename, FLAC__int64 filesize, stream_data_struct *stream_data, output_config_t *config);\r
+void FLAC_plugin__decoder_finish(FLAC__StreamDecoder *decoder);\r
+void FLAC_plugin__decoder_delete(FLAC__StreamDecoder *decoder);\r
+\r
+int FLAC_plugin__seek(FLAC__StreamDecoder *decoder, stream_data_struct *stream_data);\r
+unsigned FLAC_plugin__decode(FLAC__StreamDecoder *decoder, stream_data_struct *stream_data, char *sample_buffer);\r
+int FLAC_plugin__get_rate(unsigned written_time, unsigned output_time, stream_data_struct *stream_data);\r
+\r
+/*\r
+ *  these should be defined in plug-in\r
+ */\r
+\r
+extern void FLAC_plugin__show_error(const char *message,...);\r
diff --git a/src/plugin_winamp2/resource.h b/src/plugin_winamp2/resource.h
new file mode 100644 (file)
index 0000000..f09b4af
--- /dev/null
@@ -0,0 +1,47 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Developer Studio generated include file.\r
+// Used by resource.rc\r
+//\r
+#define IDC_RESET                       3\r
+#define IDD_CONFIG                      101\r
+#define IDD_CONFIG_GENERAL              103\r
+#define IDD_CONFIG_OUTPUT               104\r
+#define IDD_INFOBOX                     105\r
+#define IDC_ENABLE                      1000\r
+#define IDC_ALBUM                       1001\r
+#define IDC_LIMITER                     1002\r
+#define IDC_COMMENT                     1002\r
+#define IDC_PREAMP                      1003\r
+#define IDC_YEAR                        1003\r
+#define IDC_PA                          1004\r
+#define IDC_TRACK                       1004\r
+#define IDC_DITHER                      1005\r
+#define IDC_DITHERRG                    1006\r
+#define IDC_TO                          1008\r
+#define IDC_SHAPE                       1009\r
+#define IDC_TABS                        1009\r
+#define IDC_TITLE                       1010\r
+#define IDC_TAGZ_HELP                   1011\r
+#define IDC_ARTIST                      1011\r
+#define IDC_TAGZ_DEFAULT                1012\r
+#define IDC_SEP                         1013\r
+#define IDC_NAME                        1014\r
+#define IDC_INFO                        1015\r
+#define IDC_GENRE                       1017\r
+#define IDC_REMOVE                      1020\r
+#define IDC_UPDATE                      1021\r
+#define IDC_ID3V1                       1030\r
+#define IDC_RESERVE                     1032\r
+#define IDC_BPS                         1036\r
+#define IDC_ERRORS                      1037\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        106\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1037\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/src/plugin_winamp2/resource.rc b/src/plugin_winamp2/resource.rc
new file mode 100644 (file)
index 0000000..4689e3e
--- /dev/null
@@ -0,0 +1,236 @@
+//Microsoft Developer Studio generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Russian resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT\r
+#pragma code_page(1251)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_INFOBOX DIALOG DISCARDABLE  0, 0, 292, 148\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    EDITTEXT        IDC_NAME,3,3,285,12,ES_AUTOHSCROLL | ES_READONLY | NOT \r
+                    WS_TABSTOP\r
+    GROUPBOX        " Tag  ",IDC_STATIC,3,20,182,104\r
+    RTEXT           "&Title",IDC_STATIC,8,32,31,8\r
+    EDITTEXT        IDC_TITLE,43,30,137,12,ES_AUTOHSCROLL\r
+    RTEXT           "&Artist",IDC_STATIC,8,47,31,8\r
+    EDITTEXT        IDC_ARTIST,43,45,137,12,ES_AUTOHSCROLL\r
+    RTEXT           "Albu&m",IDC_STATIC,8,62,31,8\r
+    EDITTEXT        IDC_ALBUM,43,60,137,12,ES_AUTOHSCROLL\r
+    RTEXT           "&Comment",IDC_STATIC,8,77,31,8\r
+    EDITTEXT        IDC_COMMENT,43,75,137,12,ES_AUTOHSCROLL\r
+    RTEXT           "&Date",IDC_STATIC,8,92,31,8\r
+    EDITTEXT        IDC_YEAR,43,90,40,12,ES_AUTOHSCROLL\r
+    RTEXT           "Track &number",IDC_STATIC,90,92,46,8\r
+    EDITTEXT        IDC_TRACK,141,90,39,12,ES_AUTOHSCROLL\r
+    RTEXT           "&Genre",IDC_STATIC,8,107,31,8\r
+    COMBOBOX        IDC_GENRE,43,105,137,95,CBS_DROPDOWN | CBS_SORT | \r
+                    WS_VSCROLL | WS_TABSTOP\r
+    GROUPBOX        " FLAC Info  ",IDC_STATIC,191,20,97,124\r
+    LTEXT           "",IDC_INFO,195,30,90,110\r
+    DEFPUSHBUTTON   "Close",IDOK,3,130,50,14\r
+    PUSHBUTTON      "&Update",IDC_UPDATE,69,130,50,14\r
+    PUSHBUTTON      "&Remove",IDC_REMOVE,135,130,50,14\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO DISCARDABLE \r
+BEGIN\r
+    IDD_INFOBOX, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 285\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 141\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // Russian resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_CONFIG DIALOG DISCARDABLE  0, 0, 237, 212\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "FLAC Configuration"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    DEFPUSHBUTTON   "OK",IDOK,75,195,50,14\r
+    PUSHBUTTON      "Cancel",IDCANCEL,129,195,50,14\r
+    PUSHBUTTON      "Reset",IDC_RESET,183,195,50,14\r
+    CONTROL         "Tab1",IDC_TABS,"SysTabControl32",WS_TABSTOP,3,3,230,187\r
+END\r
+\r
+IDD_CONFIG_GENERAL DIALOG DISCARDABLE  0, 0, 226, 171\r
+STYLE DS_CONTROL | WS_CHILD\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    GROUPBOX        " Title Formatting  ",IDC_STATIC,2,2,220,58\r
+    LTEXT           "&Title",IDC_STATIC,8,17,14,8\r
+    EDITTEXT        IDC_TITLE,27,15,188,12,ES_AUTOHSCROLL\r
+    PUSHBUTTON      "default",IDC_TAGZ_DEFAULT,156,28,30,10\r
+    PUSHBUTTON      "help",IDC_TAGZ_HELP,188,28,27,10\r
+    LTEXT           "Separate tag values &with",IDC_STATIC,8,43,79,8\r
+    EDITTEXT        IDC_SEP,91,41,27,12,ES_AUTOHSCROLL\r
+    CONTROL         "Read ID3v&1 tags",IDC_ID3V1,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,147,43,70,10\r
+    GROUPBOX        " Tag Editor  ",IDC_STATIC,2,63,220,30\r
+    CONTROL         "Reserve space for &FLAC tags",IDC_RESERVE,"Button",\r
+                    BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,8,76,125,10\r
+    GROUPBOX        " Miscellaneous  ",IDC_STATIC,2,96,220,72\r
+    CONTROL         "&Show instantaneous bitrate while playing",IDC_BPS,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,8,108,125,10\r
+    CONTROL         "Stop on &all errors",IDC_ERRORS,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,8,120,69,10\r
+END\r
+\r
+IDD_CONFIG_OUTPUT DIALOG DISCARDABLE  0, 0, 224, 171\r
+STYLE DS_CONTROL | WS_CHILD\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    GROUPBOX        " ReplayGain  ",IDC_STATIC,2,2,220,57\r
+    CONTROL         "&Enable ReplayGain",IDC_ENABLE,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,8,15,77,10\r
+    CONTROL         "&Album mode",IDC_ALBUM,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,8,27,55,10\r
+    CONTROL         "6dB &hard limiter",IDC_LIMITER,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,123,27,64,10\r
+    LTEXT           "&Preamp",IDC_STATIC,8,44,25,8\r
+    CONTROL         "Slider1",IDC_PREAMP,"msctls_trackbar32",TBS_NOTICKS | \r
+                    WS_TABSTOP,36,43,154,12\r
+    RTEXT           "",IDC_PA,194,44,21,8\r
+    GROUPBOX        " Resolution  ",IDC_STATIC,1,62,220,95\r
+    GROUPBOX        " Without ReplayGain ",IDC_STATIC,7,71,209,30\r
+    CONTROL         "&Dither 24bps to 16bps",IDC_DITHER,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,84,85,10\r
+    GROUPBOX        " With ReplayGain ",IDC_STATIC,7,104,209,47\r
+    LTEXT           "&Output bit depth",IDC_STATIC,16,119,52,8\r
+    COMBOBOX        IDC_TO,71,116,39,43,CBS_DROPDOWNLIST | WS_VSCROLL | \r
+                    WS_TABSTOP\r
+    CONTROL         "E&nable dithering",IDC_DITHERRG,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,134,67,10\r
+    LTEXT           "Noise &shaping",IDC_STATIC,113,135,46,8\r
+    COMBOBOX        IDC_SHAPE,164,132,46,48,CBS_DROPDOWNLIST | WS_VSCROLL | \r
+                    WS_TABSTOP\r
+    LTEXT           "Note: changes take effect after restarting playback",\r
+                    IDC_STATIC,2,160,161,8\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO DISCARDABLE \r
+BEGIN\r
+    IDD_CONFIG, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 230\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 205\r
+    END\r
+\r
+    IDD_CONFIG_GENERAL, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 219\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 164\r
+    END\r
+\r
+    IDD_CONFIG_OUTPUT, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 217\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 164\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/src/plugin_winamp2/tagz.cpp b/src/plugin_winamp2/tagz.cpp
new file mode 100644 (file)
index 0000000..475f3c2
--- /dev/null
@@ -0,0 +1,921 @@
+#include <string.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+#include "tagz.h"\r
+\r
+#ifdef TAGZ_UNICODE\r
+\r
+#define _TX(X)      L##X\r
+#define t_strdup    wcsdup\r
+#define t_strlen    wcslen\r
+#define t_strnicmp  wcsnicmp\r
+#define t_atoi(x)   wcstol(x,0,10)\r
+#define t_stricmp   wcsicmp\r
+#define t_strstr    wcsstr\r
+#define sprintf     swprintf\r
+\r
+#else\r
+\r
+#define _TX(X)      X\r
+#define t_strdup    strdup\r
+#define t_strlen    strlen\r
+#define t_strnicmp  strnicmp\r
+#define t_atoi      atoi\r
+#define t_stricmp   stricmp\r
+#define t_strstr    strstr\r
+\r
+#endif\r
+\r
+#define TABSIZE(x) (sizeof(x)/sizeof(x[0]))\r
+\r
+\r
+class T_String\r
+{\r
+private:\r
+       T_CHAR * data;\r
+       UINT size,used;\r
+public:\r
+       T_String() {data=0;size=0;used=0;}\r
+       void AddChar(T_CHAR c)\r
+       {\r
+               if (!data)\r
+               {\r
+                       data=(T_CHAR*)malloc((size=512)*sizeof(T_CHAR));\r
+                       used=0;\r
+               }\r
+               else if (size==used)\r
+               {\r
+                       size<<=1;\r
+                       data=(T_CHAR*)realloc((char*)data,size*sizeof(T_CHAR));\r
+               }\r
+               if (data) data[used++]=c;               \r
+       }\r
+       void AddInt(int i)\r
+       {\r
+               T_CHAR foo[16];\r
+               sprintf(foo,_TX("%i"),i);\r
+               AddString(foo);\r
+       }\r
+       void AddString(const T_CHAR * z)\r
+       {\r
+               while(*z) {AddChar(*z);z++;}\r
+       }\r
+       void AddString(T_String & s)\r
+       {\r
+               AddString(s.Peek());\r
+       }\r
+       ~T_String()\r
+       {\r
+               if (data) free(data);\r
+       }\r
+       T_CHAR * GetBuf()\r
+       {\r
+               if (!data) return ::t_strdup(_TX(""));\r
+               T_CHAR * r=(T_CHAR*)realloc(data,(used+1)*sizeof(T_CHAR));\r
+               r[used]=0;\r
+               data=0;\r
+               return r;\r
+       }\r
+       T_CHAR operator[](UINT i)\r
+       {\r
+               if (!data || i>=used) return 0;\r
+               else return data[i];\r
+       }\r
+       UINT Len() {return data ? used : 0;}\r
+       void Reset()\r
+       {\r
+               if (data) {free(data);data=0;}          \r
+       }\r
+       const T_CHAR * Peek()\r
+       {\r
+               AddChar(0);\r
+               used--;\r
+               return data;\r
+       }\r
+       T_CHAR * strdup()\r
+       {\r
+               return ::t_strdup(Peek());\r
+       }\r
+};\r
+\r
+\r
+\r
+\r
+static int separator(T_CHAR x)\r
+{\r
+       if (!x || x==' ') return 1;\r
+       if (x=='\'' || x=='_') return 0;\r
+#ifdef TAGZ_UNICODE\r
+       return !iswalnum(x);\r
+#else\r
+       return !isalnum(x);\r
+#endif\r
+}\r
+\r
+static int sepcmp(T_CHAR* src,T_CHAR* val)\r
+{\r
+       UINT l=t_strlen(val);\r
+       return !t_strnicmp(src,val,l) && separator(src[l]);\r
+}\r
+\r
+static char roman_num[]=\r
+{\r
+       'I','V','X','L','C','D','M'\r
+};\r
+\r
+\r
+static int is_roman(T_CHAR * ptr)/* could be more smart i think */\r
+{\r
+       if (ptr[0]==']' && ptr[1]=='[' && separator(ptr[2])) return 1;\r
+       while(!separator(*ptr))\r
+       {\r
+               UINT n;\r
+               bool found=0;\r
+               for(n=0;n<TABSIZE(roman_num);n++)\r
+               {\r
+                       if (*ptr==roman_num[n]) {found=1;break;}\r
+               }\r
+               if (!found) return 0;\r
+               ptr++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static int need_full(T_CHAR* ptr)\r
+{\r
+       if (is_roman(ptr)) return 1;\r
+       if (sepcmp(ptr,_TX("RPG"))) return 1;\r
+       while(!separator(*ptr))\r
+       {\r
+               if (*ptr<'0' || *ptr>'9') return 0;\r
+               ptr++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+typedef bool (*TEXTFUNC)(UINT n_src,T_CHAR **src,UINT*,T_String &out);\r
+\r
+#define MAKEFUNC(X) static bool X(UINT n_src,T_CHAR ** src,UINT *found_src,T_String &out)\r
+\r
+\r
+MAKEFUNC(If)\r
+{\r
+       if (n_src!=3) return false;\r
+\r
+       out.AddString(src[found_src[0] ? 1 : 2]);\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(If2)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       out.AddString(src[found_src[0] ? 0 : 1]);\r
+       return true;\r
+}\r
+\r
+\r
+MAKEFUNC(Iflonger)\r
+{\r
+       if (n_src!=4) return false;\r
+\r
+       out.AddString(src[(int)t_strlen(src[0])>t_atoi(src[1]) ? 2 : 3]);\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Ifgreater)\r
+{\r
+       if (n_src!=4) return false;\r
+\r
+       out.AddString(src[t_atoi(src[0])>t_atoi(src[1]) ? 2 : 3]);\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Upper)\r
+{\r
+       if (n_src!=1) return false;\r
+\r
+       T_CHAR * s=src[0];\r
+\r
+       while(*s)\r
+               out.AddChar(toupper(*(s++)));\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Lower)\r
+{\r
+       if (n_src!=1) return false;\r
+\r
+       T_CHAR * s=src[0];\r
+\r
+       while(*s)\r
+               out.AddChar(tolower(*(s++)));\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Pad)\r
+{\r
+       if (n_src<2 || n_src>3) return false;\r
+\r
+       T_CHAR *fill=_TX(" ");\r
+       if (n_src==3 && src[2][0])\r
+               fill = src[2];\r
+\r
+       int num = t_atoi(src[1]);\r
+       T_CHAR *p = src[0];\r
+\r
+       while (*p) { out.AddChar(*(p++)); num--; }\r
+\r
+       UINT fl = t_strlen(fill);\r
+       while (num>0)\r
+               out.AddChar(fill[(--num)%fl]);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Cut)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       UINT num = t_atoi(src[1]);\r
+       T_CHAR *p = src[0];\r
+\r
+       while (*p && num>0) {out.AddChar(*(p++));num--;}\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(PadCut)\r
+{\r
+       if (n_src<2 || n_src>3) return false;\r
+\r
+       T_CHAR *fill = _TX(" ");\r
+       if (n_src==3 && src[2][0])\r
+               fill = src[2];\r
+\r
+       int num = t_atoi(src[1]);\r
+       T_CHAR *p = src[0];\r
+\r
+       while(*p && num>0) {out.AddChar(*(p++));num--;}\r
+\r
+       UINT fl=t_strlen(fill);\r
+       while (num>0)\r
+               out.AddChar(fill[(--num)%fl]);\r
+\r
+       return true;\r
+}\r
+\r
+/* abbr(string) */\r
+/* abbr(string,len) */\r
+MAKEFUNC(Abbr)\r
+{\r
+       if (n_src==0 || n_src>2) return false;\r
+\r
+\r
+       if (n_src==2 && (int)t_strlen(src[0])<t_atoi(src[1]))\r
+       {\r
+               out.AddString(src[0]);\r
+               return true;\r
+       }\r
+\r
+       T_CHAR * meta=src[0];\r
+       bool w=0, r=0;\r
+\r
+       while(*meta)\r
+       {\r
+               bool an=!separator(*meta) || *meta==']' || *meta=='[';\r
+\r
+               if (w && !an)\r
+                       w=0;\r
+               else if (!w && an)\r
+               {\r
+                       w=1;\r
+                       r=need_full(meta)?1:0;\r
+                       out.AddChar(*meta);\r
+               }\r
+               else if (w && r)\r
+                       out.AddChar(*meta);\r
+               meta++;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+\r
+MAKEFUNC(Caps)\r
+{\r
+       if (n_src!=1) return false;\r
+\r
+       T_CHAR* sp=src[0];\r
+       int sep = 1;\r
+\r
+       while(*sp)\r
+       {\r
+               T_CHAR c=*(sp++);\r
+               int s = separator(c);\r
+               if (!s && sep)\r
+                       c=toupper(c);\r
+               else if (!sep) c=tolower(c);\r
+               sep=s;\r
+               out.AddChar(c);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Caps2)\r
+{\r
+       if (n_src!=1) return false;\r
+\r
+       T_CHAR* sp=src[0];\r
+       int sep=1;\r
+\r
+       while(*sp)\r
+       {\r
+               T_CHAR c=*(sp++);\r
+               int s = separator(c);\r
+               if (!s && sep)\r
+                       c=toupper(c);\r
+               sep=s;\r
+               out.AddChar(c);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Longest)\r
+{\r
+       T_CHAR *ptr=0;\r
+       UINT n, m=0;\r
+\r
+       for(n=0;n<n_src;n++)\r
+       {\r
+               UINT l=t_strlen(src[n]);\r
+               if (l>m) {m=l;ptr=src[n];}\r
+       }\r
+\r
+       if (ptr) out.AddString(ptr);\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Shortest)\r
+{\r
+       T_CHAR * ptr=0;\r
+       UINT n,m=(UINT)(-1);\r
+\r
+       for(n=0;n<n_src;n++)\r
+       {\r
+               UINT l=t_strlen(src[n]);\r
+               if (l<m) {m=l;ptr=src[n];}\r
+       }\r
+\r
+       if (ptr) out.AddString(ptr);\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Num)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       T_CHAR tmp[16];\r
+       T_CHAR tmp1[16];\r
+       sprintf(tmp1,_TX("%%0%uu"),t_atoi(src[1]));\r
+       sprintf(tmp,tmp1,t_atoi(src[0]));\r
+       out.AddString(tmp);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Hex)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       T_CHAR tmp[16];\r
+       T_CHAR tmp1[16];\r
+       sprintf(tmp1,_TX("%%0%ux"),t_atoi(src[1]));\r
+       sprintf(tmp,tmp1,t_atoi(src[0]));\r
+       out.AddString(tmp);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(StrChr)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       T_CHAR * p=src[0];\r
+       T_CHAR s=src[1][0];\r
+\r
+       while (*p && *p!=s) p++;\r
+       if (*p==s)\r
+               out.AddInt(1+p-src[0]);\r
+       else out.AddChar('0');\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(StrRChr)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       T_CHAR * p=src[0],*p1=0;\r
+       T_CHAR s=src[1][0];\r
+\r
+       while(*p)\r
+       {\r
+               if (*p==s) p1=p;\r
+               p++;\r
+       }\r
+\r
+       if (p1)\r
+               out.AddInt(1+p1-src[0]);\r
+       else out.AddChar('0');\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(StrStr)\r
+{\r
+       if (n_src!=2) return false;\r
+\r
+       T_CHAR * p = t_strstr(src[0],src[1]);\r
+\r
+       if (p)\r
+               out.AddInt(1+p-src[0]);\r
+       else out.AddChar('0');\r
+\r
+       return true;\r
+}\r
+\r
+/* substr(string, index) */\r
+/* substr(string, index, length) */\r
+MAKEFUNC(SubStr)\r
+{\r
+       if (n_src<2 || n_src>3) return false;\r
+\r
+       int n1 = t_atoi(src[1]), n2;\r
+\r
+       if (n_src == 3)\r
+               n2 = t_atoi(src[2]);\r
+       else n2 = n1;\r
+\r
+       if (n1 < 1) n1=1;\r
+       if (n2 >= n1)\r
+       {\r
+               n1--;\r
+               n2--;\r
+               while(n1<=n2 && src[0][n1])\r
+                       out.AddChar(src[0][n1++]);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Len)\r
+{\r
+       if (n_src!=1) return false;\r
+\r
+       out.AddInt(t_strlen(src[0]));\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Add)\r
+{\r
+       UINT n;\r
+       int s=0;\r
+\r
+       for (n=0;n<n_src;n++)\r
+               s+=t_atoi(src[n]);\r
+\r
+       out.AddInt(s);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Sub)\r
+{\r
+       if (n_src==0) return false;\r
+\r
+       UINT n;\r
+       int s=t_atoi(src[0]);\r
+\r
+       for (n=1;n<n_src;n++)\r
+               s-=t_atoi(src[n]);\r
+\r
+       out.AddInt(s);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Mul)\r
+{\r
+       UINT n;\r
+       int s=1;\r
+\r
+       for(n=0;n<n_src;n++)\r
+               s*=t_atoi(src[n]);\r
+\r
+       out.AddInt(s);\r
+\r
+       return true;\r
+}\r
+                               \r
+MAKEFUNC(Div)\r
+{\r
+       if (n_src==0) return false;\r
+\r
+       UINT n;\r
+       int s=t_atoi(src[0]);\r
+\r
+       for(n=1;n<n_src;n++)\r
+       {\r
+               int t=t_atoi(src[n]);\r
+               if (t) s/=t;\r
+               else t=0;\r
+       }\r
+\r
+       out.AddInt(s);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Mod)\r
+{\r
+       if (n_src==0) return false;\r
+\r
+       UINT n;\r
+       int s=t_atoi(src[0]);\r
+\r
+       for(n=1;n<n_src;n++)\r
+       {\r
+               int t=t_atoi(src[n]);\r
+               if (t) s%=t;\r
+               else t=0;\r
+       }\r
+\r
+       out.AddInt(s);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Max)\r
+{\r
+       if (!n_src) return false;\r
+\r
+       int m = t_atoi(src[0]);\r
+       UINT n;\r
+\r
+       for (n=1; n<n_src; n++)\r
+       {\r
+               int t = t_atoi(src[n]);\r
+               if (t > m) m = t;\r
+       }\r
+       out.AddInt(m);\r
+\r
+       return true;\r
+}\r
+\r
+MAKEFUNC(Min)\r
+{\r
+       if (!n_src) return false;\r
+\r
+       int m=t_atoi(src[0]);\r
+       UINT n;\r
+\r
+       for(n=1;n<n_src;n++)\r
+       {\r
+               int t=t_atoi(src[n]);\r
+               if (t<m) m=t;\r
+       }\r
+       out.AddInt(m);\r
+\r
+       return true;\r
+}\r
+\r
+/* replace(string, what_to_replace, replacement) */\r
+MAKEFUNC(Replace)\r
+{\r
+       if (n_src!=3) return false;\r
+       T_CHAR *p = src[0];\r
+\r
+       while (*p)\r
+       {\r
+               UINT n=0;\r
+\r
+               while (src[1][n] && p[n]==src[1][n]) n++;\r
+\r
+               if (!src[1][n])\r
+               {\r
+                       out.AddString(src[2]);\r
+                       p += n;\r
+               }\r
+               else out.AddChar(*p++);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+struct\r
+{\r
+       TEXTFUNC func;\r
+       const T_CHAR * name;\r
+}\r
+FUNCS[] =\r
+{\r
+       If,_TX("if"),\r
+       If2,_TX("if2"),\r
+       Upper,_TX("upper"),\r
+       Lower,_TX("lower"),\r
+       Pad,_TX("pad"),\r
+       Cut,_TX("cut"),\r
+       PadCut,_TX("padcut"),\r
+       Abbr,_TX("abbr"),\r
+       Caps,_TX("caps"),\r
+       Caps2,_TX("caps2"),\r
+       Longest,_TX("longest"),\r
+       Shortest,_TX("shortest"),\r
+       Iflonger,_TX("iflonger"),\r
+       Ifgreater,_TX("ifgreater"),\r
+       Num,_TX("num"),Num,_TX("dec"),\r
+       Hex,_TX("hex"),\r
+       StrChr,_TX("strchr"),\r
+       StrChr,_TX("strlchr"),\r
+       StrRChr,_TX("strrchr"),\r
+       StrStr,_TX("strstr"),\r
+       SubStr,_TX("substr"),\r
+       Len,_TX("len"),\r
+       Add,_TX("add"),\r
+       Sub,_TX("sub"),\r
+       Mul,_TX("mul"),\r
+       Div,_TX("div"),\r
+       Mod,_TX("mod"),\r
+       Min,_TX("min"),\r
+       Max,_TX("max"),\r
+       Replace,_TX("replace"),\r
+};\r
+\r
+\r
+class FMT\r
+{\r
+private:\r
+       T_String str;\r
+       T_CHAR * spec;\r
+       TAGFUNC f;\r
+       TAGFREEFUNC ff;\r
+       void * fp;\r
+       T_CHAR * org_spec;\r
+       int found;\r
+\r
+       void Error(T_CHAR *e=0)\r
+       {\r
+               str.Reset();\r
+               str.AddString(e ? e : _TX("[SYNTAX ERROR IN FORMATTING STRING]"));\r
+               found++;  /* force displaying */\r
+       }\r
+\r
+       T_CHAR * _FMT(T_CHAR * s,UINT *f=0)\r
+       {\r
+               FMT fmt(this,s);\r
+               T_CHAR * c=(T_CHAR*)fmt;\r
+               if (f) *f=fmt.found;\r
+               found+=fmt.found;\r
+               return c;\r
+       }\r
+\r
+       static bool skipshit(T_CHAR** _p,T_CHAR *bl)\r
+       {\r
+               T_CHAR * p=*_p;\r
+               int bc1=0,bc2=0;\r
+               while(*p)\r
+               {\r
+                       if (!bc1 && !bc2 && bl)\r
+                       {\r
+                               T_CHAR *z=bl;\r
+                               while(*z)\r
+                               {\r
+                                       if (*z==*p) break;\r
+                                       z++;\r
+                               }\r
+                               if (*z) break;                          \r
+                       }\r
+                       if (*p=='\'')\r
+                       {\r
+                               p++;\r
+                               while(*p && *p!='\'') p++;\r
+                               if (!*p) return 0;\r
+                       }\r
+                       else if (*p=='(') bc1++;\r
+                       else if (*p==')')\r
+                       {\r
+                               if (--bc1<0) return 0;\r
+                       }\r
+                       else if (*p=='[') bc2++;\r
+                       else if (*p==']')\r
+                       {\r
+                               if (--bc2<0) return 0;\r
+                       }\r
+                       p++;\r
+               }\r
+               *_p=p;\r
+               return *p && !bc1 && !bc2;\r
+       }\r
+\r
+       void run()\r
+       {\r
+               if (!spec) {Error();return;}\r
+               while(*spec)\r
+               {\r
+                       if (*spec=='%')\r
+                       {\r
+                               spec++;\r
+                               if (*spec=='%') {str.AddChar('%');spec++;continue;}\r
+                               T_CHAR* s1=spec+1;\r
+                               while(*s1 && *s1!='%') s1++;\r
+                               if (!*s1) {Error();break;}\r
+                               *s1=0;\r
+                               T_CHAR * tag=f(spec,fp);\r
+                               *s1='%';\r
+                               /*if (!tag) tag=tag_unknown; */\r
+                               if (tag && tag[0])\r
+                               {\r
+                                       found++;\r
+                                       str.AddString(tag);\r
+                               }\r
+                               else\r
+                               {\r
+                                       str.AddString(_TX("?"));\r
+                               }\r
+                               if (tag && ff) ff(tag,fp);\r
+                               spec=s1+1;\r
+                       }\r
+                       else if (*spec=='$')\r
+                       {\r
+                               spec++;\r
+                               if (*spec=='$') {str.AddChar('$');spec++;continue;}\r
+                               T_CHAR * s1=spec+1;\r
+                               while(*s1 && *s1!='(') s1++;\r
+                               if (!*s1) {Error();break;}\r
+                               T_CHAR * s2=s1+1;\r
+                               if (!skipshit(&s2,_TX(")"))) {Error();break;}\r
+                               if (!*s2) {Error();break;};\r
+                               T_CHAR * p=s1+1;\r
+                               T_CHAR* temp[64];\r
+                               UINT temp_f[64];\r
+                               UINT nt=0;\r
+                               T_CHAR * p1=s1+1;\r
+                               while(p<=s2 && nt<64)\r
+                               {\r
+                                       if (!skipshit(&p,_TX(",)"))) {Error();return;}\r
+                                       if (p>s2 || (*p!=',' && *p!=')')) {Error(_TX("internal error"));return;}\r
+                                       T_CHAR bk=*p;\r
+                                       *p=0;\r
+                                       temp[nt]=_FMT(p1,&temp_f[nt]);\r
+                                       nt++;\r
+                                       *p=bk;;\r
+                                       p1=p+1;\r
+                                       p++;\r
+                               }\r
+                               *s1=0;\r
+                               UINT n;\r
+\r
+                               for (n=0; n<TABSIZE(FUNCS); n++)\r
+                                       if (!t_stricmp(spec, FUNCS[n].name))\r
+                                               break;\r
+\r
+                               *s1='(';\r
+\r
+                               if (n != TABSIZE(FUNCS))\r
+                               {\r
+                                       if (!FUNCS[n].func(nt, temp, temp_f, str))\r
+                                       {\r
+                                               Error(_TX("[INVALID $"));\r
+                                               str.AddString(FUNCS[n].name);\r
+                                               str.AddString(_TX(" SYNTAX]"));\r
+                                               return;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       Error(_TX("[UNKNOWN FUNCTION]"));\r
+                                       return;\r
+                               }\r
+\r
+                               for(n=0;n<nt;n++) free(temp[n]);\r
+                               spec=s2+1;\r
+                       }\r
+                       else if (*spec=='\'')\r
+                       {\r
+                               spec++;\r
+                               if (*spec=='\'') {str.AddChar('\'');spec++;continue;}\r
+                               T_CHAR * s1=spec+1;\r
+                               while(*s1 && *s1!='\'') s1++;\r
+                               if (!*s1) {Error();break;}\r
+                               *s1=0;\r
+                               str.AddString(spec);\r
+                               *s1='\'';\r
+                               spec=s1+1;\r
+                       }\r
+                       else if (*spec=='[')\r
+                       {\r
+                               spec++;\r
+                               T_CHAR * s1=spec;\r
+                               UINT bc=0;\r
+                               if (!skipshit(&s1,_TX("]"))) {Error();break;}\r
+                               T_CHAR bk=*s1;\r
+                               *s1=0;\r
+                               FMT fmt(this,spec);\r
+                               fmt.run();\r
+                               if (fmt.found)\r
+                               {\r
+                                       str.AddString(fmt.str);\r
+                                       found+=fmt.found;\r
+                               }\r
+                               *s1=bk;\r
+                               spec=s1+1;\r
+                       }\r
+                       else if (*spec == ']') {Error();break;}\r
+                       else\r
+                       {\r
+                               str.AddChar(*spec);\r
+                               spec++;\r
+                       }\r
+               }\r
+       }\r
+\r
+       FMT(FMT* base,T_CHAR * _spec)\r
+       {\r
+               found=0;\r
+               org_spec=0;\r
+               f=base->f;\r
+               ff=base->ff;\r
+               fp=base->fp;\r
+               spec=_spec;\r
+       }\r
+public:\r
+       FMT(const T_CHAR * p_spec,TAGFUNC _f,TAGFREEFUNC _ff,void * _fp)\r
+       {\r
+               found=0;\r
+               org_spec=spec=t_strdup(p_spec);\r
+               f=_f;\r
+               ff=_ff;\r
+               fp=_fp;\r
+       }\r
+       operator T_CHAR*()\r
+       {\r
+               run();\r
+               return str.GetBuf();\r
+       }\r
+       ~FMT()\r
+       {\r
+               if (org_spec) free(org_spec);\r
+       }\r
+};\r
+\r
+extern "C"\r
+{\r
+\r
+UINT tagz_format(const T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR* out,UINT max)\r
+{\r
+       T_CHAR * zz=tagz_format_r(spec,f,ff,fp);\r
+       UINT r=0;\r
+       while(r<max-1 && zz[r])\r
+       {\r
+               out[r]=zz[r];\r
+               r++;\r
+       }\r
+       out[r]=0;\r
+       free(zz);\r
+       return r;\r
+}      \r
+\r
+T_CHAR * tagz_format_r(const T_CHAR* spec,TAGFUNC f,TAGFREEFUNC ff,void * fp)\r
+{\r
+       return FMT(spec,f,ff,fp);\r
+}\r
+\r
+const char tagz_manual[]="Syntax reference: \n"\r
+       "\n"\r
+       "* %tagname% - inserts field named <tagname>, eg. \"%artist%\"\n"\r
+       "* $abbr(x) - inserts abbreviation of x, eg. \"$abbr(%album%)\" - will convert album name of \"Final Fantasy VI\" to \"FFVI\"\n"\r
+       "* $abbr(x,y) - inserts abbreviation of x if x is longer than y characters; otherwise inserts full value of x, eg. \"$abbr(%album%,10)\"\n"\r
+       "* $lower(x), $upper(x) - converts x to in lower/uppercase, eg. \"$upper(%title%)\"\n"\r
+       "* $num(x,y) - displays x number and pads with zeros up to y characters (useful for track numbers), eg. $num(%tracknumber%,2)\n"\r
+       "* $caps(x) - converts first letter in every word of x to uppercase, and all other letters to lowercase, eg. \"blah BLAH\" -> \"Blah Blah\"\n"\r
+       "* $caps2(x) - similar to $caps, but leaves uppercase letters as they are, eg. \"blah BLAH\" -> \"Blah BLAH\"\n"\r
+       "* $if(A,B,C) - if A contains at least one valid tag, displays B, otherwise displays C; eg. \"$if(%artist%,%artist%,unknown artist)\" will display artist name if present; otherwise will display \"unknown artist\"; note that \"$if(A,A,)\" is equivalent to \"[A]\" (see below)\n"\r
+       "* $if2(A,B) - equals to $if(A,A,B)\n"\r
+       "* $longest(A,B,C,....) - compares lengths of output strings produced by A,B,C... and displays the longest one, eg. \"$longest(%title%,%comment%)\" will display either title if it's longer than comment; otherwise it will display comment\n"\r
+       "* $pad(x,y) - pads x with spaces up to y characters\n"\r
+       "* $cut(x,y) - truncates x to y characters\n"\r
+       "* $padcut(x,y) - pads x to y characters and truncates to y if longer\n"\r
+       "* [ .... ] - displays contents of brackets only if at least one of fields referenced inside has been found, eg. \"%artist% - [%album% / ]%title%\" will hide [] block if album field is not present\n"\r
+       "* \' (single quotation mark) - outputs raw text without parsing, eg, \'blah$blah%blah[][]\' will output the contained string and ignore all reserved characters (%,$,[,]) in it; you can use this feature to insert square brackets for an example.\n"\r
+       "\n"\r
+       "eg. \"[%artist% - ][$abbr(%album%,10)[ %tracknumber%] / ]%title%[ %streamtitle%]\"\n";\r
+\r
+\r
+}\r
diff --git a/src/plugin_winamp2/tagz.h b/src/plugin_winamp2/tagz.h
new file mode 100644 (file)
index 0000000..0862293
--- /dev/null
@@ -0,0 +1,32 @@
+#pragma once\r
+\r
+#ifdef  __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifndef UINT\r
+typedef unsigned int UINT;\r
+#endif\r
+\r
+#ifdef TAGZ_UNICODE\r
+#if _MSC_VER <= 1200\r
+typedef unsigned short T_CHAR;\r
+#else\r
+typedef wchar_t T_CHAR;\r
+#endif\r
+#else\r
+#define T_CHAR char\r
+#endif\r
+\r
+typedef T_CHAR* (*TAGFUNC)(const T_CHAR *tag,void *p);    /* return 0 if not found */\r
+typedef void (*TAGFREEFUNC)(T_CHAR *tag,void *p);\r
+\r
+\r
+UINT tagz_format(const T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR * out,UINT max);\r
+T_CHAR * tagz_format_r(const T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void * fp);\r
+\r
+extern const char tagz_manual[];\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
diff --git a/src/plugin_xmms/Makefile.am b/src/plugin_xmms/Makefile.am
new file mode 100644 (file)
index 0000000..62ca2ab
--- /dev/null
@@ -0,0 +1,70 @@
+#  libxmms-flac - XMMS FLAC input plugin
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+EXTRA_DIST = \
+       Makefile.lite
+
+noinst_HEADERS = \
+       charset.h \
+       configure.h \
+       http.h \
+       locale_hack.h \
+       plugin.h \
+       tag.h
+
+AM_CFLAGS = @OGG_CFLAGS@ @XMMS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/src
+if FLaC__INSTALL_XMMS_PLUGIN_LOCALLY
+xmmsinputplugindir = $(HOME)/.xmms/Plugins
+else
+xmmsinputplugindir = @XMMS_INPUT_PLUGIN_DIR@
+endif
+
+# Don't build a static library
+LIBTOOL = $(top_builddir)/libtool-disable-static
+
+xmmsinputplugin_LTLIBRARIES = libxmms-flac.la
+
+plugin_sources = charset.c configure.c fileinfo.c http.c plugin.c tag.c
+
+libxmms_flac_la_SOURCES = $(plugin_sources)
+
+# work around the bug in libtool where its relinking fails with a different DESTDIR
+# for libtool bug info see:
+#   http://mail.gnu.org/pipermail/bug-libtool/2002-February/003018.html
+#   http://mail.gnu.org/pipermail/libtool/2002-April/006244.html
+#   http://mail.gnu.org/pipermail/libtool/2002-April/006250.html
+# for fix info see:
+#   http://lists.freshrpms.net/pipermail/rpm-list/2002-April/000746.html
+# the workaround is the extra '-L$(top_builddir)/src/libFLAC/.libs'
+libxmms_flac_la_LIBADD = \
+       $(top_builddir)/src/plugin_common/libplugin_common.la \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+       $(top_builddir)/src/share/utf8/libutf8.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       -L$(top_builddir)/src/libFLAC/.libs \
+       @OGG_LIBS@ \
+       @XMMS_LIBS@ \
+       @LIBICONV@
+libxmms_flac_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugin_xmms/Makefile.lite b/src/plugin_xmms/Makefile.lite
new file mode 100644 (file)
index 0000000..6addb9d
--- /dev/null
@@ -0,0 +1,43 @@
+#  libxmms-flac - XMMS FLAC input plugin
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+
+LIB_NAME  = libxmms-flac
+INCLUDES  = -I./include -I$(topdir)/include -I.. $(shell xmms-config --cflags)
+# refer to the static libs explicitly
+ifeq ($(DARWIN_BUILD),yes)
+LIBS = $(topdir)/obj/$(BUILD)/lib/libFLAC.a $(topdir)/obj/$(BUILD)/lib/libplugin_common.a $(topdir)/obj/$(BUILD)/lib/libgrabbag.a $(topdir)/obj/$(BUILD)/lib/libreplaygain_analysis.a $(topdir)/obj/$(BUILD)/lib/libreplaygain_synthesis.a $(OGG_LIB_DIR)/libogg.a -liconv -lstdc++ -lz
+else
+LIBS = $(topdir)/obj/$(BUILD)/lib/libFLAC.a $(topdir)/obj/$(BUILD)/lib/libplugin_common.a $(topdir)/obj/$(BUILD)/lib/libgrabbag.a $(topdir)/obj/$(BUILD)/lib/libreplaygain_analysis.a $(topdir)/obj/$(BUILD)/lib/libreplaygain_synthesis.a -L$(OGG_LIB_DIR) -logg -lstdc++ -lz
+endif
+
+SRCS_C = \
+       charset.c \
+       configure.c \
+       plugin.c \
+       fileinfo.c \
+       http.c \
+       tag.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/plugin_xmms/charset.c b/src/plugin_xmms/charset.c
new file mode 100644 (file)
index 0000000..c79e2ef
--- /dev/null
@@ -0,0 +1,198 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ * Almost from charset.c
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  HÃ¥vard KvÃ¥len <havardk@xmms.org>
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "plugin_common/charset.h"
+#include "charset.h"
+#include "configure.h"
+#include "locale_hack.h"
+
+
+/****************
+ * Declarations *
+ ****************/
+
+#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) )
+const CharsetInfo charset_trans_array[] = {
+       {N_("Arabic (IBM-864)"),                  "IBM864"        },
+       {N_("Arabic (ISO-8859-6)"),               "ISO-8859-6"    },
+       {N_("Arabic (Windows-1256)"),             "windows-1256"  },
+       {N_("Baltic (ISO-8859-13)"),              "ISO-8859-13"   },
+       {N_("Baltic (ISO-8859-4)"),               "ISO-8859-4"    },
+       {N_("Baltic (Windows-1257)"),             "windows-1257"  },
+       {N_("Celtic (ISO-8859-14)"),              "ISO-8859-14"   },
+       {N_("Central European (IBM-852)"),        "IBM852"        },
+       {N_("Central European (ISO-8859-2)"),     "ISO-8859-2"    },
+       {N_("Central European (Windows-1250)"),   "windows-1250"  },
+       {N_("Chinese Simplified (GB18030)"),      "gb18030"       },
+       {N_("Chinese Simplified (GB2312)"),       "GB2312"        },
+       {N_("Chinese Traditional (Big5)"),        "Big5"          },
+       {N_("Chinese Traditional (Big5-HKSCS)"),  "Big5-HKSCS"    },
+       {N_("Cyrillic (IBM-855)"),                "IBM855"        },
+       {N_("Cyrillic (ISO-8859-5)"),             "ISO-8859-5"    },
+       {N_("Cyrillic (ISO-IR-111)"),             "ISO-IR-111"    },
+       {N_("Cyrillic (KOI8-R)"),                 "KOI8-R"        },
+       {N_("Cyrillic (Windows-1251)"),           "windows-1251"  },
+       {N_("Cyrillic/Russian (CP-866)"),         "IBM866"        },
+       {N_("Cyrillic/Ukrainian (KOI8-U)"),       "KOI8-U"        },
+       {N_("English (US-ASCII)"),                "us-ascii"      },
+       {N_("Greek (ISO-8859-7)"),                "ISO-8859-7"    },
+       {N_("Greek (Windows-1253)"),              "windows-1253"  },
+       {N_("Hebrew (IBM-862)"),                  "IBM862"        },
+       {N_("Hebrew (Windows-1255)"),             "windows-1255"  },
+       {N_("Japanese (EUC-JP)"),                 "EUC-JP"        },
+       {N_("Japanese (ISO-2022-JP)"),            "ISO-2022-JP"   },
+       {N_("Japanese (Shift_JIS)"),              "Shift_JIS"     },
+       {N_("Korean (EUC-KR)"),                   "EUC-KR"        },
+       {N_("Nordic (ISO-8859-10)"),              "ISO-8859-10"   },
+       {N_("South European (ISO-8859-3)"),       "ISO-8859-3"    },
+       {N_("Thai (TIS-620)"),                    "TIS-620"       },
+       {N_("Turkish (IBM-857)"),                 "IBM857"        },
+       {N_("Turkish (ISO-8859-9)"),              "ISO-8859-9"    },
+       {N_("Turkish (Windows-1254)"),            "windows-1254"  },
+       {N_("Unicode (UTF-7)"),                   "UTF-7"         },
+       {N_("Unicode (UTF-8)"),                   "UTF-8"         },
+       {N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
+       {N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
+       {N_("Unicode (UTF-32BE)"),                "UTF-32BE"      },
+       {N_("Unicode (UTF-32LE)"),                "UTF-32LE"      },
+       {N_("Vietnamese (VISCII)"),               "VISCII"        },
+       {N_("Vietnamese (Windows-1258)"),         "windows-1258"  },
+       {N_("Visual Hebrew (ISO-8859-8)"),        "ISO-8859-8"    },
+       {N_("Western (IBM-850)"),                 "IBM850"        },
+       {N_("Western (ISO-8859-1)"),              "ISO-8859-1"    },
+       {N_("Western (ISO-8859-15)"),             "ISO-8859-15"   },
+       {N_("Western (Windows-1252)"),            "windows-1252"  }
+
+       /*
+        * From this point, character sets aren't supported by iconv
+        */
+#if 0
+       {N_("Arabic (IBM-864-I)"),                "IBM864i"              },
+       {N_("Arabic (ISO-8859-6-E)"),             "ISO-8859-6-E"         },
+       {N_("Arabic (ISO-8859-6-I)"),             "ISO-8859-6-I"         },
+       {N_("Arabic (MacArabic)"),                "x-mac-arabic"         },
+       {N_("Armenian (ARMSCII-8)"),              "armscii-8"            },
+       {N_("Central European (MacCE)"),          "x-mac-ce"             },
+       {N_("Chinese Simplified (GBK)"),          "x-gbk"                },
+       {N_("Chinese Simplified (HZ)"),           "HZ-GB-2312"           },
+       {N_("Chinese Traditional (EUC-TW)"),      "x-euc-tw"             },
+       {N_("Croatian (MacCroatian)"),            "x-mac-croatian"       },
+       {N_("Cyrillic (MacCyrillic)"),            "x-mac-cyrillic"       },
+       {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian"      },
+       {N_("Farsi (MacFarsi)"),                  "x-mac-farsi"},
+       {N_("Greek (MacGreek)"),                  "x-mac-greek"          },
+       {N_("Gujarati (MacGujarati)"),            "x-mac-gujarati"       },
+       {N_("Gurmukhi (MacGurmukhi)"),            "x-mac-gurmukhi"       },
+       {N_("Hebrew (ISO-8859-8-E)"),             "ISO-8859-8-E"         },
+       {N_("Hebrew (ISO-8859-8-I)"),             "ISO-8859-8-I"         },
+       {N_("Hebrew (MacHebrew)"),                "x-mac-hebrew"         },
+       {N_("Hindi (MacDevanagari)"),             "x-mac-devanagari"     },
+       {N_("Icelandic (MacIcelandic)"),          "x-mac-icelandic"      },
+       {N_("Korean (JOHAB)"),                    "x-johab"              },
+       {N_("Korean (UHC)"),                      "x-windows-949"        },
+       {N_("Romanian (MacRomanian)"),            "x-mac-romanian"       },
+       {N_("Turkish (MacTurkish)"),              "x-mac-turkish"        },
+       {N_("User Defined"),                      "x-user-defined"       },
+       {N_("Vietnamese (TCVN)"),                 "x-viet-tcvn5712"      },
+       {N_("Vietnamese (VPS)"),                  "x-viet-vps"           },
+       {N_("Western (MacRoman)"),                "x-mac-roman"          },
+       /* charsets whithout posibly translatable names */
+       {"T61.8bit",                              "T61.8bit"             },
+       {"x-imap4-modified-utf7",                 "x-imap4-modified-utf7"},
+       {"x-u-escaped",                           "x-u-escaped"          },
+       {"windows-936",                           "windows-936"          }
+#endif
+};
+
+/*************
+ * Functions *
+ *************/
+
+/*
+ * Commons conversion functions
+ */
+char *convert_from_utf8_to_user(const char *string)
+{
+       return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set);
+}
+
+char *convert_from_user_to_utf8(const char *string)
+{
+       return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8");
+}
+
+GList *Charset_Create_List (void)
+{
+       GList *list = NULL;
+       guint i;
+
+       for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+               list = g_list_append(list,_(charset_trans_array[i].charset_title));
+       return list;
+}
+
+GList *Charset_Create_List_UTF8_Only (void)
+{
+       GList *list = NULL;
+
+       list = g_list_append(list,_(Charset_Get_Title_From_Name("UTF-8")));
+       return list;
+}
+
+
+/*
+ * Return charset_name from charset_title
+ */
+gchar *Charset_Get_Name_From_Title (gchar *charset_title)
+{
+       guint i;
+
+       if (charset_title)
+               for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+                       if ( strcasecmp(_(charset_title),_(charset_trans_array[i].charset_title)) == 0 )
+                               return charset_trans_array[i].charset_name;
+       return "";
+}
+
+
+/*
+ * Return charset_title from charset_name
+ */
+gchar *Charset_Get_Title_From_Name (gchar *charset_name)
+{
+       guint i;
+
+       if (charset_name)
+               for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+                       if ( strcasecmp(charset_name,charset_trans_array[i].charset_name) == 0 )
+                               return _(charset_trans_array[i].charset_title);
+       return "";
+}
diff --git a/src/plugin_xmms/charset.h b/src/plugin_xmms/charset.h
new file mode 100644 (file)
index 0000000..6ed42c7
--- /dev/null
@@ -0,0 +1,56 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ * Almost from charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kvè™±en <havardk@xmms.org>
+ *
+ *  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__PLUGIN_XMMS__CHARSET_H
+#define FLAC__PLUGIN_XMMS__CHARSET_H
+
+
+/***************
+ * Declaration *
+ ***************/
+
+typedef struct {
+       gchar *charset_title;
+       gchar *charset_name;
+} CharsetInfo;
+
+/* translated charset titles */
+extern const CharsetInfo charset_trans_array[];
+
+/**************
+ * Prototypes *
+ **************/
+
+/*
+ * The returned strings are malloc()ed an must be free()d by the caller
+ */
+char *convert_from_utf8_to_user(const char *string);
+char *convert_from_user_to_utf8(const char *string);
+
+GList *Charset_Create_List (void);
+GList *Charset_Create_List_UTF8_Only (void);
+gchar *Charset_Get_Name_From_Title (gchar *charset_title);
+gchar *Charset_Get_Title_From_Name (gchar *charset_name);
+
+#endif /* __CHARSET_H__ */
+
diff --git a/src/plugin_xmms/configure.c b/src/plugin_xmms/configure.c
new file mode 100644 (file)
index 0000000..f9170e9
--- /dev/null
@@ -0,0 +1,823 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *          and prefs.c - 2000/05/06
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 2000-2002  Jerome Couderc <j.couderc@ifrance.com>
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <pthread.h>
+#include <math.h>
+
+#include <xmms/configfile.h>
+#include <xmms/dirbrowser.h>
+#include <xmms/titlestring.h>
+#include <xmms/util.h>
+#include <xmms/plugin.h>
+
+#include "share/replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */
+#include "charset.h"
+#include "configure.h"
+#include "locale_hack.h"
+
+/*
+ * Initialize Global Valueable
+ */
+flac_config_t flac_cfg = {
+       /* title */
+       {
+               FALSE, /* tag_override */
+               NULL, /* tag_format */
+               FALSE, /* convert_char_set */
+               NULL /* user_char_set */
+       },
+       /* stream */
+       {
+               100 /* KB */, /* http_buffer_size */
+               50, /* http_prebuffer */
+               FALSE, /* use_proxy */
+               NULL, /* proxy_host */
+               0, /* proxy_port */
+               FALSE, /* proxy_use_auth */
+               NULL, /* proxy_user */
+               NULL, /* proxy_pass */
+               FALSE, /* save_http_stream */
+               NULL, /* save_http_path */
+               FALSE, /* cast_title_streaming */
+               FALSE /* use_udp_channel */
+       },
+       /* output */
+       {
+               /* replaygain */
+               {
+                       FALSE, /* enable */
+                       TRUE, /* album_mode */
+                       0, /* preamp */
+                       FALSE /* hard_limit */
+               },
+               /* resolution */
+               {
+                       /* normal */
+                       {
+                               TRUE /* dither_24_to_16 */
+                       },
+                       /* replaygain */
+                       {
+                               TRUE, /* dither */
+                               NOISE_SHAPING_LOW, /* noise_shaping */
+                               16 /* bps_out */
+                       }
+               }
+       }
+};
+
+
+static GtkWidget *flac_configurewin = NULL;
+static GtkWidget *vbox, *notebook;
+
+static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc;
+static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry;
+static GtkWidget *replaygain_enable, *replaygain_album_mode;
+static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit;
+static GtkObject *replaygain_preamp;
+static GtkWidget *resolution_normal_dither_24_to_16;
+static GtkWidget *resolution_replaygain_dither;
+static GtkWidget *resolution_replaygain_noise_shaping_frame;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_none;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_low;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_medium;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_high;
+static GtkWidget *resolution_replaygain_bps_out_frame;
+static GtkWidget *resolution_replaygain_bps_out_radio_16bps;
+static GtkWidget *resolution_replaygain_bps_out_radio_24bps;
+
+static GtkObject *streaming_size_adj, *streaming_pre_adj;
+static GtkWidget *streaming_proxy_use, *streaming_proxy_host_entry;
+static GtkWidget *streaming_proxy_port_entry, *streaming_save_use, *streaming_save_entry;
+static GtkWidget *streaming_proxy_auth_use;
+static GtkWidget *streaming_proxy_auth_pass_entry, *streaming_proxy_auth_user_entry;
+static GtkWidget *streaming_proxy_auth_user_label, *streaming_proxy_auth_pass_label;
+#ifdef FLAC_ICECAST
+static GtkWidget *streaming_cast_title, *streaming_udp_title;
+#endif
+static GtkWidget *streaming_proxy_hbox, *streaming_proxy_auth_hbox, *streaming_save_dirbrowser;
+static GtkWidget *streaming_save_hbox;
+
+static gchar *gtk_entry_get_text_1 (GtkWidget *widget);
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data);
+static void configure_destroy(GtkWidget * w, gpointer data);
+
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
+{
+       ConfigFile *cfg;
+       gchar *filename;
+
+       (void)widget, (void)data; /* unused arguments */
+       g_free(flac_cfg.title.tag_format);
+       flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry)));
+       flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry));
+
+       filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
+       cfg = xmms_cfg_open_file(filename);
+       if (!cfg)
+               cfg = xmms_cfg_new();
+       /* title */
+       xmms_cfg_write_boolean(cfg, "flac", "title.tag_override", flac_cfg.title.tag_override);
+       xmms_cfg_write_string(cfg, "flac", "title.tag_format", flac_cfg.title.tag_format);
+       xmms_cfg_write_boolean(cfg, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set);
+       xmms_cfg_write_string(cfg, "flac", "title.user_char_set", flac_cfg.title.user_char_set);
+       /* output */
+       xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable);
+       xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode);
+       xmms_cfg_write_int(cfg, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp);
+       xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit);
+       xmms_cfg_write_boolean(cfg, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16);
+       xmms_cfg_write_boolean(cfg, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither);
+       xmms_cfg_write_int(cfg, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping);
+       xmms_cfg_write_int(cfg, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out);
+       /* streaming */
+       flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value;
+       flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value;
+
+       flac_cfg.stream.use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+       if(flac_cfg.stream.proxy_host)
+               g_free(flac_cfg.stream.proxy_host);
+       flac_cfg.stream.proxy_host = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_host_entry)));
+       flac_cfg.stream.proxy_port = atoi(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_port_entry)));
+
+       flac_cfg.stream.proxy_use_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+       if(flac_cfg.stream.proxy_user)
+               g_free(flac_cfg.stream.proxy_user);
+       flac_cfg.stream.proxy_user = NULL;
+       if(strlen(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_user_entry))) > 0)
+               flac_cfg.stream.proxy_user = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_user_entry)));
+
+       if(flac_cfg.stream.proxy_pass)
+               g_free(flac_cfg.stream.proxy_pass);
+       flac_cfg.stream.proxy_pass = NULL;
+       if(strlen(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_pass_entry))) > 0)
+               flac_cfg.stream.proxy_pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_proxy_auth_pass_entry)));
+
+
+       flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+       if (flac_cfg.stream.save_http_path)
+               g_free(flac_cfg.stream.save_http_path);
+       flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry)));
+
+#ifdef FLAC_ICECAST
+       flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title));
+       flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title));
+#endif
+
+       xmms_cfg_write_int(cfg, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size);
+       xmms_cfg_write_int(cfg, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer);
+       xmms_cfg_write_boolean(cfg, "flac", "stream.use_proxy", flac_cfg.stream.use_proxy);
+       xmms_cfg_write_string(cfg, "flac", "stream.proxy_host", flac_cfg.stream.proxy_host);
+       xmms_cfg_write_int(cfg, "flac", "stream.proxy_port", flac_cfg.stream.proxy_port);
+       xmms_cfg_write_boolean(cfg, "flac", "stream.proxy_use_auth", flac_cfg.stream.proxy_use_auth);
+       if(flac_cfg.stream.proxy_user)
+               xmms_cfg_write_string(cfg, "flac", "stream.proxy_user", flac_cfg.stream.proxy_user);
+       else
+               xmms_cfg_remove_key(cfg, "flac", "stream.proxy_user");
+       if(flac_cfg.stream.proxy_pass)
+               xmms_cfg_write_string(cfg, "flac", "stream.proxy_pass", flac_cfg.stream.proxy_pass);
+       else
+               xmms_cfg_remove_key(cfg, "flac", "stream.proxy_pass");
+       xmms_cfg_write_boolean(cfg, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream);
+       xmms_cfg_write_string(cfg, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path);
+#ifdef FLAC_ICECAST
+       xmms_cfg_write_boolean(cfg, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming);
+       xmms_cfg_write_boolean(cfg, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel);
+#endif
+
+       xmms_cfg_write_file(cfg, filename);
+       xmms_cfg_free(cfg);
+       g_free(filename);
+       gtk_widget_destroy(flac_configurewin);
+}
+
+static void configure_destroy(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+}
+
+static void title_tag_override_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override));
+
+       gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+       gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+
+}
+
+static void convert_char_set_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set));
+
+       gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+       gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+}
+
+static void replaygain_enable_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable));
+
+       gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable);
+       gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable);
+       gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable);
+}
+
+static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode));
+}
+
+static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit));
+}
+
+static void replaygain_preamp_cb(GtkWidget *widget, gpointer data)
+{
+       GString *gstring = g_string_new("");
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5);
+
+       g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp);
+       gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str));
+}
+
+static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16));
+}
+
+static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither));
+
+       gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither);
+}
+
+static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.resolution.replaygain.noise_shaping =
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 :
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 :
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 :
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 :
+               0
+       ;
+}
+
+static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data)
+{
+       (void)widget, (void)data; /* unused arguments */
+       flac_cfg.output.resolution.replaygain.bps_out =
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 :
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 :
+               16
+       ;
+}
+
+static void proxy_use_cb(GtkWidget * w, gpointer data)
+{
+       gboolean use_proxy, use_proxy_auth;
+       (void) w;
+       (void) data;
+
+       use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+       use_proxy_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+       gtk_widget_set_sensitive(streaming_proxy_hbox, use_proxy);
+       gtk_widget_set_sensitive(streaming_proxy_auth_use, use_proxy);
+       gtk_widget_set_sensitive(streaming_proxy_auth_hbox, use_proxy && use_proxy_auth);
+}
+
+static void proxy_auth_use_cb(GtkWidget *w, gpointer data)
+{
+       gboolean use_proxy, use_proxy_auth;
+       (void) w;
+       (void) data;
+
+       use_proxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_use));
+       use_proxy_auth = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use));
+
+       gtk_widget_set_sensitive(streaming_proxy_auth_hbox, use_proxy && use_proxy_auth);
+}
+
+static void streaming_save_dirbrowser_cb(gchar * dir)
+{
+       gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir);
+}
+
+static void streaming_save_browse_cb(GtkWidget * w, gpointer data)
+{
+       (void) w;
+       (void) data;
+       if (!streaming_save_dirbrowser)
+       {
+               streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"),
+                                                                   flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb);
+               gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser);
+               gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin));
+               gtk_widget_show(streaming_save_dirbrowser);
+       }
+}
+
+static void streaming_save_use_cb(GtkWidget * w, gpointer data)
+{
+       gboolean save_stream;
+       (void) w;
+       (void) data;
+
+       save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+
+       gtk_widget_set_sensitive(streaming_save_hbox, save_stream);
+}
+
+
+void FLAC_XMMS__configure(void)
+{
+       GtkWidget *title_frame, *title_tag_vbox, *title_tag_label;
+       GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame;
+       GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox;
+       GtkWidget *resolution_replaygain_noise_shaping_vbox;
+       GtkWidget *resolution_replaygain_bps_out_vbox;
+       GtkWidget *label, *hbox;
+       GtkWidget *bbox, *ok, *cancel;
+       GList *list;
+
+       GtkWidget *streaming_vbox;
+       GtkWidget *streaming_buf_frame, *streaming_buf_hbox;
+       GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin;
+       GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin;
+       GtkWidget *streaming_proxy_frame, *streaming_proxy_vbox;
+       GtkWidget *streaming_proxy_port_label, *streaming_proxy_host_label;
+       GtkWidget *streaming_save_frame, *streaming_save_vbox;
+       GtkWidget *streaming_save_label, *streaming_save_browse;
+#ifdef FLAC_ICECAST
+       GtkWidget *streaming_cast_frame, *streaming_cast_vbox;
+#endif
+       char *temp;
+
+       if (flac_configurewin != NULL) {
+               gdk_window_raise(flac_configurewin->window);
+               return;
+       }
+       flac_configurewin = gtk_window_new(GTK_WINDOW_DIALOG);
+       gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin);
+       gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin);
+       gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration"));
+       gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE);
+       gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10);
+
+       vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox);
+
+       notebook = gtk_notebook_new();
+       gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+       /* Title config.. */
+
+       title_frame = gtk_frame_new(_("Tag Handling"));
+       gtk_container_border_width(GTK_CONTAINER(title_frame), 5);
+
+       title_tag_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox);
+
+       /* Convert Char Set */
+
+       convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set);
+       gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", convert_char_set_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0);
+       /*  Combo boxes... */
+       hbox = gtk_hbox_new(FALSE,4);
+       gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox);
+       label = gtk_label_new(_("Convert character set from :"));
+       gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+       fileCharacterSetEntry = gtk_combo_new();
+       gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0);
+
+       label = gtk_label_new (_("to :"));
+       gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+       userCharacterSetEntry = gtk_combo_new();
+       gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0);
+
+       gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE);
+       gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE);
+       gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE);
+       gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE);
+
+       list = Charset_Create_List();
+       gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only());
+       gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list);
+       gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set));
+       gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+       gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+
+       /* Override Tagging Format */
+
+       title_tag_override = gtk_check_button_new_with_label(_("Override generic titles"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override);
+       gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", title_tag_override_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0);
+
+       title_tag_box = gtk_hbox_new(FALSE, 5);
+       gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+       gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0);
+
+       title_tag_label = gtk_label_new(_("Title format:"));
+       gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0);
+
+       title_tag_entry = gtk_entry_new();
+       gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format);
+       gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0);
+
+       title_desc = xmms_titlestring_descriptions("pafFetnygc", 2);
+       gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+       gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0);
+
+       gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title")));
+
+       /* Output config.. */
+
+       output_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(output_vbox), 5);
+
+       /* replaygain */
+
+       replaygain_frame = gtk_frame_new(_("ReplayGain"));
+       gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5);
+       gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0);
+
+       replaygain_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox);
+
+       replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable);
+       gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", replaygain_enable_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0);
+
+       replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode);
+       gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", replaygain_album_mode_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0);
+
+       hbox = gtk_hbox_new(FALSE,3);
+       gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox);
+       label = gtk_label_new(_("Preamp:"));
+       gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+       replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0);
+       gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", replaygain_preamp_cb, NULL);
+       replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp));
+       gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE);
+       gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0);
+       replaygain_preamp_label = gtk_label_new(_("0 dB"));
+       gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0);
+       gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp));
+
+       replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit);
+       gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", replaygain_hard_limit_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0);
+
+       replaygain_enable_cb(replaygain_enable, NULL);
+
+       /* resolution */
+
+       resolution_frame = gtk_frame_new(_("Resolution"));
+       gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5);
+       gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0);
+
+       resolution_hbox = gtk_hbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5);
+       gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox);
+
+       resolution_normal_frame = gtk_frame_new(_("Without ReplayGain"));
+       gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5);
+       gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0);
+
+       resolution_normal_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox);
+
+       resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16);
+       gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", resolution_normal_dither_24_to_16_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0);
+
+       resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain"));
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5);
+       gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0);
+
+       resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox);
+
+       resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", resolution_replaygain_dither_cb, NULL);
+       gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0);
+
+       hbox = gtk_hbox_new(FALSE, 10);
+       gtk_container_border_width(GTK_CONTAINER(hbox), 5);
+       gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0);
+
+       resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping"));
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5);
+       gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0);
+
+       resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new();
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox);
+
+       resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none"));
+       if(flac_cfg.output.resolution.replaygain.noise_shaping == 0)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none);
+
+       resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low"));
+       if(flac_cfg.output.resolution.replaygain.noise_shaping == 1)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low);
+
+       resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium"));
+       if(flac_cfg.output.resolution.replaygain.noise_shaping == 2)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium);
+
+       resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high"));
+       if(flac_cfg.output.resolution.replaygain.noise_shaping == 3)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", resolution_replaygain_noise_shaping_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high);
+
+       resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to"));
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5);
+       gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0);
+
+       resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new();
+       gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox);
+
+       resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps"));
+       if(flac_cfg.output.resolution.replaygain.bps_out == 16)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", resolution_replaygain_bps_out_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps);
+
+       resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps"));
+       if(flac_cfg.output.resolution.replaygain.bps_out == 24)
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE);
+       gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", resolution_replaygain_bps_out_cb, NULL);
+       gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps);
+
+       resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL);
+
+       gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output")));
+
+       /* Streaming */
+
+       streaming_vbox = gtk_vbox_new(FALSE, 0);
+
+       streaming_buf_frame = gtk_frame_new(_("Buffering:"));
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5);
+       gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0);
+
+       streaming_buf_hbox = gtk_hbox_new(TRUE, 5);
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5);
+       gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox);
+
+       streaming_size_box = gtk_hbox_new(FALSE, 5);
+       /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */
+       gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0);
+       streaming_size_label = gtk_label_new(_("Buffer size (kb):"));
+       gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0);
+       streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4);
+       streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0);
+       gtk_widget_set_usize(streaming_size_spin, 60, -1);
+       gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0);
+
+       streaming_pre_box = gtk_hbox_new(FALSE, 5);
+       /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */
+       gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0);
+       streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):"));
+       gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0);
+       streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1);
+       streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0);
+       gtk_widget_set_usize(streaming_pre_spin, 60, -1);
+       gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0);
+
+       /*
+        * Proxy config.
+        */
+       streaming_proxy_frame = gtk_frame_new(_("Proxy:"));
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_proxy_frame), 5);
+       gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_proxy_frame, FALSE, FALSE, 0);
+
+       streaming_proxy_vbox = gtk_vbox_new(FALSE, 5);
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_proxy_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(streaming_proxy_frame), streaming_proxy_vbox);
+
+       streaming_proxy_use = gtk_check_button_new_with_label(_("Use proxy"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_proxy_use), flac_cfg.stream.use_proxy);
+       gtk_signal_connect(GTK_OBJECT(streaming_proxy_use), "clicked", GTK_SIGNAL_FUNC(proxy_use_cb), NULL);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_use, FALSE, FALSE, 0);
+
+       streaming_proxy_hbox = gtk_hbox_new(FALSE, 5);
+       gtk_widget_set_sensitive(streaming_proxy_hbox, flac_cfg.stream.use_proxy);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_hbox, FALSE, FALSE, 0);
+
+       streaming_proxy_host_label = gtk_label_new(_("Host:"));
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_host_label, FALSE, FALSE, 0);
+
+       streaming_proxy_host_entry = gtk_entry_new();
+       gtk_entry_set_text(GTK_ENTRY(streaming_proxy_host_entry), flac_cfg.stream.proxy_host? flac_cfg.stream.proxy_host : "");
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_host_entry, TRUE, TRUE, 0);
+
+       streaming_proxy_port_label = gtk_label_new(_("Port:"));
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_port_label, FALSE, FALSE, 0);
+
+       streaming_proxy_port_entry = gtk_entry_new();
+       gtk_widget_set_usize(streaming_proxy_port_entry, 50, -1);
+       temp = g_strdup_printf("%d", flac_cfg.stream.proxy_port);
+       gtk_entry_set_text(GTK_ENTRY(streaming_proxy_port_entry), temp);
+       g_free(temp);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_hbox), streaming_proxy_port_entry, FALSE, FALSE, 0);
+
+       streaming_proxy_auth_use = gtk_check_button_new_with_label(_("Use authentication"));
+       gtk_widget_set_sensitive(streaming_proxy_auth_use, flac_cfg.stream.use_proxy);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_proxy_auth_use), flac_cfg.stream.proxy_use_auth);
+       gtk_signal_connect(GTK_OBJECT(streaming_proxy_auth_use), "clicked", GTK_SIGNAL_FUNC(proxy_auth_use_cb), NULL);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_auth_use, FALSE, FALSE, 0);
+
+       streaming_proxy_auth_hbox = gtk_hbox_new(FALSE, 5);
+       gtk_widget_set_sensitive(streaming_proxy_auth_hbox, flac_cfg.stream.use_proxy && flac_cfg.stream.proxy_use_auth);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_vbox), streaming_proxy_auth_hbox, FALSE, FALSE, 0);
+
+       streaming_proxy_auth_user_label = gtk_label_new(_("Username:"));
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_user_label, FALSE, FALSE, 0);
+
+       streaming_proxy_auth_user_entry = gtk_entry_new();
+       if(flac_cfg.stream.proxy_user)
+               gtk_entry_set_text(GTK_ENTRY(streaming_proxy_auth_user_entry), flac_cfg.stream.proxy_user);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_user_entry, TRUE, TRUE, 0);
+
+       streaming_proxy_auth_pass_label = gtk_label_new(_("Password:"));
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_pass_label, FALSE, FALSE, 0);
+
+       streaming_proxy_auth_pass_entry = gtk_entry_new();
+       if(flac_cfg.stream.proxy_pass)
+               gtk_entry_set_text(GTK_ENTRY(streaming_proxy_auth_pass_entry), flac_cfg.stream.proxy_pass);
+       gtk_entry_set_visibility(GTK_ENTRY(streaming_proxy_auth_pass_entry), FALSE);
+       gtk_box_pack_start(GTK_BOX(streaming_proxy_auth_hbox), streaming_proxy_auth_pass_entry, TRUE, TRUE, 0);
+
+
+       /*
+        * Save to disk config.
+        */
+       streaming_save_frame = gtk_frame_new(_("Save stream to disk:"));
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5);
+       gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0);
+
+       streaming_save_vbox = gtk_vbox_new(FALSE, 5);
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5);
+       gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox);
+
+       streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream);
+       gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL);
+       gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0);
+
+       streaming_save_hbox = gtk_hbox_new(FALSE, 5);
+       gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream);
+       gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0);
+
+       streaming_save_label = gtk_label_new(_("Path:"));
+       gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0);
+
+       streaming_save_entry = gtk_entry_new();
+       gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path? flac_cfg.stream.save_http_path : "");
+       gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0);
+
+       streaming_save_browse = gtk_button_new_with_label(_("Browse"));
+       gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL);
+       gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0);
+
+#ifdef FLAC_ICECAST
+       streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:"));
+       gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5);
+       gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0);
+
+       streaming_cast_vbox = gtk_vbox_new(5, FALSE);
+       gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox);
+
+       streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming);
+       gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0);
+
+       streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel);
+       gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0);
+#endif
+
+       gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming")));
+
+       /* Buttons */
+
+       bbox = gtk_hbutton_box_new();
+       gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+       gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+       gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+       ok = gtk_button_new_with_label(_("Ok"));
+       gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(flac_configurewin_ok), NULL);
+       GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+       gtk_widget_grab_default(ok);
+
+       cancel = gtk_button_new_with_label(_("Cancel"));
+       gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(flac_configurewin));
+       GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+       gtk_widget_show_all(flac_configurewin);
+}
+
+void FLAC_XMMS__aboutbox(void)
+{
+       static GtkWidget *about_window;
+
+       if (about_window)
+               gdk_window_raise(about_window->window);
+
+       about_window = xmms_show_message(
+               _("About Flac Plugin"),
+               _("Flac Plugin by Josh Coalson\n"
+                 "contributions by\n"
+                 "......\n"
+                 "......\n"
+                 "and\n"
+                 "Daisuke Shimamura\n"
+                 "Visit http://flac.sourceforge.net/"),
+               _("Ok"), FALSE, NULL, NULL);
+       gtk_signal_connect(GTK_OBJECT(about_window), "destroy",
+                          GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                          &about_window);
+}
+
+/*
+ * Get text of an Entry or a ComboBox
+ */
+static gchar *gtk_entry_get_text_1 (GtkWidget *widget)
+{
+       if (GTK_IS_COMBO(widget))
+       {
+               return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry));
+       }else if (GTK_IS_ENTRY(widget))
+       {
+               return gtk_entry_get_text(GTK_ENTRY(widget));
+       }else
+       {
+               return NULL;
+       }
+}
diff --git a/src/plugin_xmms/configure.h b/src/plugin_xmms/configure.h
new file mode 100644 (file)
index 0000000..88b2e37
--- /dev/null
@@ -0,0 +1,77 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *
+ * 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__PLUGIN_XMMS__CONFIGURE_H
+#define FLAC__PLUGIN_XMMS__CONFIGURE_H
+
+#include <glib.h>
+
+typedef struct {
+       struct {
+               gboolean tag_override;
+               gchar *tag_format;
+               gboolean convert_char_set;
+               gchar *user_char_set;
+       } title;
+
+       struct {
+               gint http_buffer_size;
+               gint http_prebuffer;
+               gboolean use_proxy; 
+               gchar *proxy_host;
+               gint proxy_port;
+               gboolean proxy_use_auth;
+               gchar *proxy_user;
+               gchar *proxy_pass;
+               gboolean save_http_stream;
+               gchar *save_http_path;
+               gboolean cast_title_streaming;
+               gboolean use_udp_channel;
+       } stream;
+
+       struct {
+               struct {
+                       gboolean enable;
+                       gboolean album_mode;
+                       gint preamp;
+                       gboolean hard_limit;
+               } replaygain;
+               struct {
+                       struct {
+                               gboolean dither_24_to_16;
+                       } normal;
+                       struct {
+                               gboolean dither;
+                               gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
+                               gint bps_out;
+                       } replaygain;
+               } resolution;
+       } output;
+} flac_config_t;
+
+extern flac_config_t flac_cfg;
+
+extern void FLAC_XMMS__configure(void);
+extern void FLAC_XMMS__aboutbox(void);
+
+#endif
+
+
+
diff --git a/src/plugin_xmms/fileinfo.c b/src/plugin_xmms/fileinfo.c
new file mode 100644 (file)
index 0000000..5589e1c
--- /dev/null
@@ -0,0 +1,496 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1999,2000  HÃ¥vard KvÃ¥len
+ *  Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ *  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h> /* for strlen() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <gtk/gtk.h>
+
+#include "FLAC/metadata.h"
+#include "charset.h"
+#include "configure.h"
+#include "plugin_common/replaygain.h"
+#include "plugin_common/tags.h"
+#include "locale_hack.h"
+
+static GtkWidget *window = NULL;
+static GList *genre_list = NULL;
+static GtkWidget *filename_entry, *tag_frame;
+static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry;
+static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak;
+static GtkWidget *genre_combo;
+static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate;
+
+static gchar *current_filename = NULL;
+static FLAC__StreamMetadata *tags_ = NULL;
+
+static const gchar *vorbis_genres[] =
+{
+       N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
+       N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
+       N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
+       N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
+       N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
+       N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
+       N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
+       N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
+       N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
+       N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"),
+       N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
+       N_("Meditative"), N_("Instrumental Pop"),
+       N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
+       N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
+       N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
+       N_("Southern Rock"), N_("Comedy"), N_("Cult"),
+       N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
+       N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
+       N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
+       N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
+       N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
+       N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
+       N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
+       N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
+       N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
+       N_("Gothic Rock"), N_("Progressive Rock"),
+       N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
+       N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
+       N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
+       N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
+       N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
+       N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
+       N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
+       N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
+       N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
+       N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
+       N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
+       N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
+       N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
+       N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
+       N_("Contemporary Christian"), N_("Christian Rock"),
+       N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
+       N_("Anime"), N_("JPop"), N_("Synthpop")
+};
+
+static void label_set_text(GtkWidget * label, char *str, ...)
+{
+       va_list args;
+       gchar *tempstr;
+
+       va_start(args, str);
+       tempstr = g_strdup_vprintf(str, args);
+       va_end(args);
+
+       gtk_label_set_text(GTK_LABEL(label), tempstr);
+       g_free(tempstr);
+}
+
+static void set_entry_tag(GtkEntry * entry, const char * utf8)
+{
+       if(utf8) {
+               if(flac_cfg.title.convert_char_set) {
+                       char *text = convert_from_utf8_to_user(utf8);
+                       gtk_entry_set_text(entry, text);
+                       free(text);
+               }
+               else
+                       gtk_entry_set_text(entry, utf8);
+       }
+       else
+               gtk_entry_set_text(entry, "");
+}
+
+static void get_entry_tag(GtkEntry * entry, const char *name)
+{
+       gchar *text;
+       char *utf8;
+
+       text = gtk_entry_get_text(entry);
+       if (!text || strlen(text) == 0)
+               return;
+       if(flac_cfg.title.convert_char_set)
+               utf8 = convert_from_user_to_utf8(text);
+       else
+               utf8 = text;
+
+       FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0);
+
+       if(flac_cfg.title.convert_char_set)
+               free(utf8);
+}
+
+static void show_tag(void)
+{
+       set_entry_tag(GTK_ENTRY(title_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE"));
+       set_entry_tag(GTK_ENTRY(artist_entry)                 , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST"));
+       set_entry_tag(GTK_ENTRY(album_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM"));
+       set_entry_tag(GTK_ENTRY(date_entry)                   , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE"));
+       set_entry_tag(GTK_ENTRY(tracknum_entry)               , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER"));
+       set_entry_tag(GTK_ENTRY(comment_entry)                , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION"));
+       set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE"));
+}
+
+static void save_tag(GtkWidget * w, gpointer data)
+{
+       (void)w;
+       (void)data;
+
+       FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+       FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+       FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+       FLAC_plugin__tags_delete_tag(tags_, "DATE");
+       FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+       FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+       FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+       get_entry_tag(GTK_ENTRY(title_entry)                  , "TITLE");
+       get_entry_tag(GTK_ENTRY(artist_entry)                 , "ARTIST");
+       get_entry_tag(GTK_ENTRY(album_entry)                  , "ALBUM");
+       get_entry_tag(GTK_ENTRY(date_entry)                   , "DATE");
+       get_entry_tag(GTK_ENTRY(tracknum_entry)               , "TRACKNUMBER");
+       get_entry_tag(GTK_ENTRY(comment_entry)                , "DESCRIPTION");
+       get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE");
+
+       FLAC_plugin__tags_set(current_filename, tags_);
+       gtk_widget_destroy(window);
+}
+
+static void remove_tag(GtkWidget * w, gpointer data)
+{
+       (void)w;
+       (void)data;
+       
+       FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+       FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+       FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+       FLAC_plugin__tags_delete_tag(tags_, "DATE");
+       FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+       FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+       FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+       FLAC_plugin__tags_set(current_filename, tags_);
+       gtk_widget_destroy(window);
+}
+
+static void show_file_info(void)
+{
+       FLAC__StreamMetadata streaminfo;
+       struct stat _stat;
+
+       gtk_label_set_text(GTK_LABEL(flac_samplerate), "");
+       gtk_label_set_text(GTK_LABEL(flac_channels), "");
+       gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), "");
+       gtk_label_set_text(GTK_LABEL(flac_blocksize), "");
+       gtk_label_set_text(GTK_LABEL(flac_filesize), "");
+       gtk_label_set_text(GTK_LABEL(flac_samples), "");
+       gtk_label_set_text(GTK_LABEL(flac_bitrate), "");
+
+       if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) {
+               return;
+       }
+
+       label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate);
+       label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels);
+       label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample);
+       if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize)
+               label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize);
+       else
+               label_set_text(flac_blocksize, _("Blocksize: variable\n  min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize);
+
+       if (streaminfo.data.stream_info.total_samples)
+               label_set_text(flac_samples, _("Samples: %llu\nLength: %d:%.2d"),
+                               streaminfo.data.stream_info.total_samples,
+                               (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60),
+                               (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60));
+
+       if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) {
+#if _FILE_OFFSET_BITS == 64
+               label_set_text(flac_filesize, _("Filesize: %lld B"), _stat.st_size);
+#else
+               label_set_text(flac_filesize, _("Filesize: %ld B"), _stat.st_size);
+#endif
+               if (streaminfo.data.stream_info.total_samples)
+                       label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"),
+                                       8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate),
+                                       100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples));
+       }
+}
+
+static void show_replaygain(void)
+{
+       /* known limitation: If only one of gain and peak is set, neither will be shown. This is true for
+        * both track and album replaygain tags. Written so it will be easy to fix, with some trouble.  */
+
+       gtk_label_set_text(GTK_LABEL(replaygain_reference), "");
+       gtk_label_set_text(GTK_LABEL(replaygain_track_gain), "");
+       gtk_label_set_text(GTK_LABEL(replaygain_album_gain), "");
+       gtk_label_set_text(GTK_LABEL(replaygain_track_peak), "");
+       gtk_label_set_text(GTK_LABEL(replaygain_album_peak), "");
+
+       double reference, track_gain, track_peak, album_gain, album_peak;
+       FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set;
+
+       if(!FLAC_plugin__replaygain_get_from_file(
+               current_filename,
+               &reference, &reference_set,
+               &track_gain, &track_gain_set,
+               &album_gain, &album_gain_set,
+               &track_peak, &track_peak_set,
+               &album_peak, &album_peak_set
+       ))
+               return;
+
+       if(reference_set)
+                 label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference);
+       if(track_gain_set)
+                 label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain);
+       if(album_gain_set)
+                 label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain);
+       if(track_peak_set)
+                 label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak);
+       if(album_peak_set)
+                 label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak);
+}
+
+void FLAC_XMMS__file_info_box(char *filename)
+{
+       unsigned i;
+       gchar *title;
+
+       if (!window)
+       {
+               GtkWidget *vbox, *hbox, *left_vbox, *table;
+               GtkWidget *flac_frame, *flac_box;
+               GtkWidget *label, *filename_hbox;
+               GtkWidget *bbox, *save, *remove, *cancel;
+
+               window = gtk_window_new(GTK_WINDOW_DIALOG);
+               gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
+               gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window);
+               gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+               vbox = gtk_vbox_new(FALSE, 10);
+               gtk_container_add(GTK_CONTAINER(window), vbox);
+
+               filename_hbox = gtk_hbox_new(FALSE, 5);
+               gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0);
+
+               label = gtk_label_new(_("Filename:"));
+               gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0);
+               filename_entry = gtk_entry_new();
+               gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE);
+               gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0);
+
+               hbox = gtk_hbox_new(FALSE, 10);
+               gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+
+               left_vbox = gtk_vbox_new(FALSE, 10);
+               gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0);
+
+               tag_frame = gtk_frame_new(_("Tag:"));
+               gtk_box_pack_start(GTK_BOX(left_vbox), tag_frame, FALSE, FALSE, 0);
+
+               table = gtk_table_new(5, 5, FALSE);
+               gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+               gtk_container_add(GTK_CONTAINER(tag_frame), table);
+
+               label = gtk_label_new(_("Title:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 5);
+
+               title_entry = gtk_entry_new();
+               gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Artist:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 5);
+
+               artist_entry = gtk_entry_new();
+               gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Album:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 5);
+
+               album_entry = gtk_entry_new();
+               gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Comment:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5);
+
+               comment_entry = gtk_entry_new();
+               gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Date:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 5);
+
+               date_entry = gtk_entry_new();
+               gtk_widget_set_usize(date_entry, 40, -1);
+               gtk_table_attach(GTK_TABLE(table), date_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Track number:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 5);
+
+               tracknum_entry = gtk_entry_new();
+               gtk_widget_set_usize(tracknum_entry, 40, -1);
+               gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               label = gtk_label_new(_("Genre:"));
+               gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+               gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 5);
+
+               genre_combo = gtk_combo_new();
+               gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), TRUE);
+
+               if (!genre_list)
+               {
+                       for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++)
+                               genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]);
+                       genre_list = g_list_prepend(genre_list, "");
+                       genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp);
+               }
+               gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list);
+
+               gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+               bbox = gtk_hbutton_box_new();
+               gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+               gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+               gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0);
+
+               save = gtk_button_new_with_label(_("Save"));
+               gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_tag), NULL);
+               GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT);
+               gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0);
+               gtk_widget_grab_default(save);
+
+               remove= gtk_button_new_with_label(_("Remove Tag"));
+               gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL);
+               GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT);
+               gtk_box_pack_start(GTK_BOX(bbox), remove, TRUE, TRUE, 0);
+
+               cancel = gtk_button_new_with_label(_("Cancel"));
+               gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
+               GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+               gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+               flac_frame = gtk_frame_new(_("FLAC Info:"));
+               gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0);
+
+               flac_box = gtk_vbox_new(FALSE, 5);
+               gtk_container_add(GTK_CONTAINER(flac_frame), flac_box);
+               gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10);
+               gtk_box_set_spacing(GTK_BOX(flac_box), 0);
+
+               flac_samplerate = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0);
+
+               flac_channels = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0);
+
+               flac_bits_per_sample = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0);
+
+               flac_blocksize = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0);
+
+               flac_filesize = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0);
+
+               flac_samples = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0);
+
+               flac_bitrate = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0);
+
+               replaygain_reference = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0);
+
+               replaygain_track_gain = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0);
+
+               replaygain_album_gain = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0);
+
+               replaygain_track_peak = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0);
+
+               replaygain_album_peak = gtk_label_new("");
+               gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0);
+               gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT);
+               gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0);
+
+               gtk_widget_show_all(window);
+       }
+
+       if(current_filename)
+               g_free(current_filename);
+       if(!(current_filename = g_strdup(filename)))
+               return;
+
+       title = g_strdup_printf(_("File Info - %s"), g_basename(filename));
+       gtk_window_set_title(GTK_WINDOW(window), title);
+       g_free(title);
+
+       gtk_entry_set_text(GTK_ENTRY(filename_entry), filename);
+       gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1);
+
+       if(tags_)
+               FLAC_plugin__tags_destroy(&tags_);
+
+       FLAC_plugin__tags_get(current_filename, &tags_);
+
+       show_tag();
+       show_file_info();
+       show_replaygain();
+
+       gtk_widget_set_sensitive(tag_frame, TRUE);
+}
diff --git a/src/plugin_xmms/http.c b/src/plugin_xmms/http.c
new file mode 100644 (file)
index 0000000..af3235f
--- /dev/null
@@ -0,0 +1,899 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  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.
+ */
+/* modified for FLAC support by Steven Richman (2003) */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <glib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+
+#include <xmms/util.h>
+#include <xmms/plugin.h>
+
+#include "FLAC/format.h"
+#include "configure.h"
+#include "locale_hack.h"
+#include "plugin.h"
+
+/* on FreeBSD we get socklen_t from <sys/socket.h> */
+#if (!defined HAVE_SOCKLEN_T) && !defined(__FreeBSD__)
+typedef unsigned int socklen_t;
+#endif
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
+#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
+
+static gchar *icy_name = NULL;
+static gint icy_metaint = 0;
+
+extern InputPlugin flac_ip;
+
+#undef DEBUG_UDP
+
+/* Static udp channel functions */
+static int udp_establish_listener (gint *sock);
+static int udp_check_for_data(gint sock);
+
+static char *flac_http_get_title(char *url);
+
+static gboolean prebuffering, going, eof = FALSE;
+static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
+static guint64 buffer_read = 0;
+static gchar *buffer;
+static guint64 offset;
+static pthread_t thread;
+static GtkWidget *error_dialog = NULL;
+
+static FILE *output_file = NULL;
+
+#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
+
+/* Encode the string S of length LENGTH to base64 format and place it
+   to STORE.  STORE will be 0-terminated, and must point to a writable
+   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
+static void base64_encode (const gchar *s, gchar *store, gint length)
+{
+       /* Conversion table.  */
+       static gchar tbl[64] = {
+               'A','B','C','D','E','F','G','H',
+               'I','J','K','L','M','N','O','P',
+               'Q','R','S','T','U','V','W','X',
+               'Y','Z','a','b','c','d','e','f',
+               'g','h','i','j','k','l','m','n',
+               'o','p','q','r','s','t','u','v',
+               'w','x','y','z','0','1','2','3',
+               '4','5','6','7','8','9','+','/'
+       };
+       gint i;
+       guchar *p = (guchar *)store;
+
+       /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
+       for (i = 0; i < length; i += 3)
+       {
+               *p++ = tbl[s[0] >> 2];
+               *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+               *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+               *p++ = tbl[s[2] & 0x3f];
+               s += 3;
+       }
+       /* Pad the result if necessary...  */
+       if (i == length + 1)
+               *(p - 1) = '=';
+       else if (i == length + 2)
+               *(p - 1) = *(p - 2) = '=';
+       /* ...and zero-terminate it.  */
+       *p = '\0';
+}
+
+/* Create the authentication header contents for the `Basic' scheme.
+   This is done by encoding the string `USER:PASS' in base64 and
+   prepending `HEADER: Basic ' to it.  */
+static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
+{
+       gchar *t1, *t2, *res;
+       gint len1 = strlen (user) + 1 + strlen (passwd);
+       gint len2 = BASE64_LENGTH (len1);
+
+       t1 = g_strdup_printf("%s:%s", user, passwd);
+       t2 = g_malloc0(len2 + 1);
+       base64_encode (t1, t2, len1);
+       res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
+       g_free(t2);
+       g_free(t1);
+       
+       return res;
+}
+
+static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
+{
+       gchar *h, *p, *pt, *f, *temp, *ptr;
+
+       temp = g_strdup(url);
+       ptr = temp;
+
+       if (!strncasecmp("http://", ptr, 7))
+               ptr += 7;
+       h = strchr(ptr, '@');
+       f = strchr(ptr, '/');
+       if (h != NULL && (!f || h < f))
+       {
+               *h = '\0';
+               p = strchr(ptr, ':');
+               if (p != NULL && p < h)
+               {
+                       *p = '\0';
+                       p++;
+                       *pass = g_strdup(p);
+               }
+               else
+                       *pass = NULL;
+               *user = g_strdup(ptr);
+               h++;
+               ptr = h;
+       }
+       else
+       {
+               *user = NULL;
+               *pass = NULL;
+               h = ptr;
+       }
+       pt = strchr(ptr, ':');
+       if (pt != NULL && (f == NULL || pt < f))
+       {
+               *pt = '\0';
+               *port = atoi(pt + 1);
+       }
+       else
+       {
+               if (f)
+                       *f = '\0';
+               *port = 80;
+       }
+       *host = g_strdup(h);
+       
+       if (f)
+               *filename = g_strdup(f + 1);
+       else
+               *filename = NULL;
+       g_free(temp);
+}
+
+void flac_http_close(void)
+{
+       going = FALSE;
+
+       pthread_join(thread, NULL);
+       g_free(icy_name);
+       icy_name = NULL;
+}
+
+
+static gint http_used(void)
+{
+       if (wr_index >= rd_index)
+               return wr_index - rd_index;
+       return buffer_length - (rd_index - wr_index);
+}
+
+static gint http_free(void)
+{
+       if (rd_index > wr_index)
+               return (rd_index - wr_index) - 1;
+       return (buffer_length - (wr_index - rd_index)) - 1;
+}
+
+static void http_wait_for_data(gint bytes)
+{
+       while ((prebuffering || http_used() < bytes) && !eof && going)
+               xmms_usleep(10000);
+}
+
+static void show_error_message(gchar *error)
+{
+       if(!error_dialog)
+       {
+               GDK_THREADS_ENTER();
+               error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
+                                                NULL, NULL);
+               gtk_signal_connect(GTK_OBJECT(error_dialog),
+                                  "destroy",
+                                  GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                                  &error_dialog);
+               GDK_THREADS_LEAVE();
+       }
+}
+
+int flac_http_read(gpointer data, gint length)
+{
+       gint len, cnt, off = 0, meta_len, meta_off = 0, i;
+       gchar *meta_data, **tags, *temp, *title;
+       if (length > buffer_length) {
+               length = buffer_length;
+       }
+
+       http_wait_for_data(length);
+
+       if (!going)
+               return 0;
+       len = min(http_used(), length);
+
+       while (len && http_used())
+       {
+               if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
+               {
+                       meta_len = *((guchar *) buffer + rd_index) * 16;
+                       rd_index = (rd_index + 1) % buffer_length;
+                       if (meta_len > 0)
+                       {
+                               http_wait_for_data(meta_len);
+                               meta_data = g_malloc0(meta_len);
+                               if (http_used() >= meta_len)
+                               {
+                                       while (meta_len)
+                                       {
+                                               cnt = min(meta_len, buffer_length - rd_index);
+                                               memcpy(meta_data + meta_off, buffer + rd_index, cnt);
+                                               rd_index = (rd_index + cnt) % buffer_length;
+                                               meta_len -= cnt;
+                                               meta_off += cnt;
+                                       }
+                                       tags = g_strsplit(meta_data, "';", 0);
+
+                                       for (i = 0; tags[i]; i++)
+                                       {
+                                               if (!strncasecmp(tags[i], "StreamTitle=", 12))
+                                               {
+                                                       temp = g_strdup(tags[i] + 13);
+                                                       title = g_strdup_printf("%s (%s)", temp, icy_name);
+                                                       set_track_info(title, -1);
+                                                       g_free(title);
+                                                       g_free(temp);
+                                               }
+
+                                       }
+                                       g_strfreev(tags);
+
+                               }
+                               g_free(meta_data);
+                       }
+                       if (!http_used())
+                               http_wait_for_data(length - off);
+                       cnt = min3(len, buffer_length - rd_index, http_used());
+               }
+               else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
+                       cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
+               else
+                       cnt = min3(len, buffer_length - rd_index, http_used());
+               if (output_file)
+                       fwrite(buffer + rd_index, 1, cnt, output_file);
+
+               memcpy((gchar *)data + off, buffer + rd_index, cnt);
+               rd_index = (rd_index + cnt) % buffer_length;
+               buffer_read += cnt;
+               len -= cnt;
+               off += cnt;
+       }
+       if (!off) {
+               fprintf(stderr, "returning zero\n");
+       }
+       return off;
+}
+
+static gboolean http_check_for_data(void)
+{
+
+       fd_set set;
+       struct timeval tv;
+       gint ret;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 20000;
+       FD_ZERO(&set);
+       FD_SET(sock, &set);
+       ret = select(sock + 1, &set, NULL, NULL, &tv);
+       if (ret > 0)
+               return TRUE;
+       return FALSE;
+}
+
+gint flac_http_read_line(gchar * buf, gint size)
+{
+       gint i = 0;
+
+       while (going && i < size - 1)
+       {
+               if (http_check_for_data())
+               {
+                       if (read(sock, buf + i, 1) <= 0)
+                               return -1;
+                       if (buf[i] == '\n')
+                               break;
+                       if (buf[i] != '\r')
+                               i++;
+               }
+       }
+       if (!going)
+               return -1;
+       buf[i] = '\0';
+       return i;
+}
+
+/* returns the file descriptor of the socket, or -1 on error */
+static int http_connect (gchar *url_, gboolean head, guint64 offset)
+{
+       gchar line[1024], *user, *pass, *host, *filename,
+            *status, *url, *temp, *file;
+       gchar *chost;
+       gint cnt, error, port, cport;
+       socklen_t err_len;
+       gboolean redirect;
+       int udp_sock = 0;
+       fd_set set;
+       struct hostent *hp;
+       struct sockaddr_in address;
+       struct timeval tv;
+
+       url = g_strdup (url_);
+
+       do
+       {
+               redirect=FALSE;
+       
+               g_strstrip(url);
+
+               parse_url(url, &user, &pass, &host, &port, &filename);
+
+               if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
+                       temp = g_strconcat(url, "/", NULL);
+               else
+                       temp = g_strdup(url);
+               g_free(url);
+               url = temp;
+
+               chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
+               cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
+
+               sock = socket(AF_INET, SOCK_STREAM, 0);
+               fcntl(sock, F_SETFL, O_NONBLOCK);
+               address.sin_family = AF_INET;
+
+               status = g_strdup_printf(_("LOOKING UP %s"), chost);
+               flac_ip.set_info_text(status);
+               g_free(status);
+
+               if (!(hp = gethostbyname(chost)))
+               {
+                       status = g_strdup_printf(_("Couldn't look up host %s"), chost);
+                       show_error_message(status);
+                       g_free(status);
+
+                       flac_ip.set_info_text(NULL);
+                       eof = TRUE;
+               }
+
+               if (!eof)
+               {
+                       memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
+                       address.sin_port = (gint) g_htons(cport);
+
+                       status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
+                       flac_ip.set_info_text(status);
+                       g_free(status);
+                       if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
+                       {
+                               if (errno != EINPROGRESS)
+                               {
+                                       status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
+                                       show_error_message(status);
+                                       g_free(status);
+
+                                       flac_ip.set_info_text(NULL);
+                                       eof = TRUE;
+                               }
+                       }
+                       while (going)
+                       {
+                               tv.tv_sec = 0;
+                               tv.tv_usec = 10000;
+                               FD_ZERO(&set);
+                               FD_SET(sock, &set);
+                               if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
+                               {
+                                       err_len = sizeof (error);
+                                       getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
+                                       if (error)
+                                       {
+                                               status = g_strdup_printf(_("Couldn't connect to host %s"),
+                                                                        chost);
+                                               show_error_message(status);
+                                               g_free(status);
+
+                                               flac_ip.set_info_text(NULL);
+                                               eof = TRUE;
+                                               
+                                       }
+                                       break;
+                               }
+                       }
+                       if (!eof)
+                       {
+                               gchar *auth = NULL, *proxy_auth = NULL;
+                               gchar udpspace[30];
+                               int udp_port;
+
+                               if (flac_cfg.stream.use_udp_channel)
+                               {
+                                       udp_port = udp_establish_listener (&udp_sock);
+                                       if (udp_port > 0) 
+                                               sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port);
+                                       else
+                                               udp_sock = 0;
+                               }
+                                       
+                               if(user && pass)
+                                       auth = basic_authentication_encode(user, pass, "Authorization");
+
+                               if (flac_cfg.stream.use_proxy)
+                               {
+                                       file = g_strdup(url);
+                                       if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
+                                       {
+                                               proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
+                                                                                        flac_cfg.stream.proxy_pass,
+                                                                                        "Proxy-Authorization");
+                                       }
+                               }
+                               else
+                                       file = g_strconcat("/", filename, NULL);
+
+                               temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
+                                                      "Host: %s\r\n"
+                                                      "User-Agent: %s/%s\r\n"
+                                                      "%s%s%s%s",
+                                                      file, host, "Reference FLAC Player", FLAC__VERSION_STRING, 
+                                                      proxy_auth ? proxy_auth : "", auth ? auth : "",
+                                                      flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
+                                                      flac_cfg.stream.use_udp_channel ? udpspace : "");
+                               if (offset && !head) {
+                                       gchar *temp_dead = temp;
+                                       temp = g_strdup_printf ("%sRange: %llu-\r\n", temp, offset);
+                                       fprintf (stderr, "%s", temp);
+                                       g_free (temp_dead);
+                               }
+                               
+                               g_free(file);
+                               if(proxy_auth)
+                                       g_free(proxy_auth);
+                               if(auth)
+                                       g_free(auth);
+                               write(sock, temp, strlen(temp));
+                               write(sock, "\r\n", 2);
+                               g_free(temp);
+                               flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
+                               while (going && !eof)
+                                 {
+                                       if (http_check_for_data())
+                                       {
+                                               if (flac_http_read_line(line, 1024))
+                                               {
+                                                       status = strchr(line, ' ');
+                                                       if (status)
+                                                       {
+                                                               if (status[1] == '2')
+                                                                       break;
+                                                               else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
+                                                               {
+                                                                       while(going)
+                                                                       {
+                                                                               if(http_check_for_data())
+                                                                               {
+                                                                                       if((cnt = flac_http_read_line(line, 1024)) != -1)
+                                                                                       {
+                                                                                               if(!cnt)
+                                                                                                       break;
+                                                                                               if(!strncmp(line, "Location:", 9))
+                                                                                               {
+                                                                                                       g_free(url);
+                                                                                                       url = g_strdup(line+10);
+                                                                                               }
+                                                                                       }
+                                                                                       else
+                                                                                       {
+                                                                                               eof=TRUE;
+                                                                                               flac_ip.set_info_text(NULL);
+                                                                                               break;
+                                                                                       }
+                                                                               }
+                                                                       }                       
+                                                                       redirect=TRUE;
+                                                                       break;
+                                                               }
+                                                               else
+                                                               {
+                                                                       status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
+                                                                       show_error_message(status);
+                                                                       g_free(status);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       eof = TRUE;
+                                                       flac_ip.set_info_text(NULL);
+                                               }
+                                       }
+                               }
+
+                               while (going && !redirect)
+                               {
+                                       if (http_check_for_data())
+                                       {
+                                               if ((cnt = flac_http_read_line(line, 1024)) != -1)
+                                               {
+                                                       if (!cnt)
+                                                               break;
+                                                       if (!strncmp(line, "icy-name:", 9))
+                                                               icy_name = g_strdup(line + 9);
+                                                       else if (!strncmp(line, "x-audiocast-name:", 17))
+                                                               icy_name = g_strdup(line + 17);
+                                                       if (!strncmp(line, "icy-metaint:", 12))
+                                                               icy_metaint = atoi(line + 12);
+                                                       if (!strncmp(line, "x-audiocast-udpport:", 20)) {
+#ifdef DEBUG_UDP
+                                                               fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
+#endif
+                                                               /*udp_serverport = atoi (line + 20);*/
+                                                       }
+                                                       
+                                               }
+                                               else
+                                               {
+                                                       eof = TRUE;
+                                                       flac_ip.set_info_text(NULL);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       
+               if(redirect)
+               {
+                       if (output_file)
+                       {
+                               fclose(output_file);
+                               output_file = NULL;
+                       }
+                       close(sock);
+               }
+
+               g_free(user);
+               g_free(pass);
+               g_free(host);
+               g_free(filename);
+       } while(redirect);
+
+       g_free(url);
+       return eof ? -1 : sock;
+}
+
+static void *http_buffer_loop(void *arg)
+{
+       gchar *status, *url, *temp, *file;
+       gint cnt, written;
+       int udp_sock = 0;
+
+       url = (gchar *) arg;
+       sock = http_connect (url, false, offset);
+       
+       if (sock >= 0 && flac_cfg.stream.save_http_stream) {
+               gchar *output_name;
+               file = flac_http_get_title(url);
+               output_name = file;
+               if (!strncasecmp(output_name, "http://", 7))
+                       output_name += 7;
+               temp = strrchr(output_name, '.');
+               if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
+                       *temp = '\0';
+
+               while ((temp = strchr(output_name, '/')))
+                       *temp = '_';
+               output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
+
+               g_free(file);
+
+               output_file = fopen(output_name, "wb");
+               g_free(output_name);
+       }
+
+       while (going)
+       {
+
+               if (!http_used() && !flac_ip.output->buffer_playing())
+                       prebuffering = TRUE;
+               if (http_free() > 0 && !eof)
+               {
+                       if (http_check_for_data())
+                       {
+                               cnt = min(http_free(), buffer_length - wr_index);
+                               if (cnt > 1024)
+                                       cnt = 1024;
+                               written = read(sock, buffer + wr_index, cnt);
+                               if (written <= 0)
+                               {
+                                       eof = TRUE;
+                                       if (prebuffering)
+                                       {
+                                               prebuffering = FALSE;
+
+                                               flac_ip.set_info_text(NULL);
+                                       }
+
+                               }
+                               else
+                                       wr_index = (wr_index + written) % buffer_length;
+                       }
+
+                       if (prebuffering)
+                       {
+                               if (http_used() > prebuffer_length)
+                               {
+                                       prebuffering = FALSE;
+                                       flac_ip.set_info_text(NULL);
+                               }
+                               else
+                               {
+                                       status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
+                                       flac_ip.set_info_text(status);
+                                       g_free(status);
+                               }
+
+                       }
+               }
+               else
+                       xmms_usleep(10000);
+
+               if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
+                       if (udp_check_for_data(udp_sock) < 0)
+                       {
+                               close(udp_sock);
+                               udp_sock = 0;
+                       }
+       }
+       if (output_file)
+       {
+               fclose(output_file);
+               output_file = NULL;
+       }
+       if (sock >= 0) {
+               close(sock);
+       }
+       if (udp_sock != 0)
+               close(udp_sock);
+
+       g_free(buffer);
+       g_free(url);
+       
+       pthread_exit(NULL);
+       return NULL; /* avoid compiler warning */
+}
+
+int flac_http_open(const gchar * _url, guint64 _offset)
+{
+       gchar *url;
+
+       url = g_strdup(_url);
+
+       rd_index = 0;
+       wr_index = 0;
+       buffer_length = flac_cfg.stream.http_buffer_size * 1024;
+       prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
+       buffer_read = 0;
+       icy_metaint = 0;
+       prebuffering = TRUE;
+       going = TRUE;
+       eof = FALSE;
+       buffer = g_malloc(buffer_length);
+       offset = _offset;
+
+       pthread_create(&thread, NULL, http_buffer_loop, url);
+
+       return 0;
+}
+
+char *flac_http_get_title(char *url)
+{
+       if (icy_name)
+               return g_strdup(icy_name);
+       if (g_basename(url) && strlen(g_basename(url)) > 0)
+               return g_strdup(g_basename(url));
+       return g_strdup(url);
+}
+
+/* Start UDP Channel specific stuff */
+
+/* Find a good local udp port and bind udp_sock to it, return the port */
+static int udp_establish_listener(int *sock)
+{
+       struct sockaddr_in sin;
+       socklen_t sinlen = sizeof (struct sockaddr_in);
+       
+#ifdef DEBUG_UDP
+       fprintf (stderr,"Establishing udp listener\n");
+#endif
+       
+       if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+       {
+               g_log(NULL, G_LOG_LEVEL_CRITICAL,
+                     "udp_establish_listener(): unable to create socket");
+               return -1;
+       }
+
+       memset(&sin, 0, sinlen);
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
+                       
+       if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
+       {
+               g_log(NULL, G_LOG_LEVEL_CRITICAL,
+                     "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
+               close(*sock);
+               return -1;
+       }
+       if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
+       {
+               g_log(NULL, G_LOG_LEVEL_CRITICAL,
+                     "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
+               close(*sock);
+               return -1;
+       }
+
+       memset(&sin, 0, sinlen);
+       if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
+       {
+               g_log(NULL, G_LOG_LEVEL_CRITICAL,
+                     "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
+               close(*sock);
+               return -1;
+       }
+
+#ifdef DEBUG_UDP
+       fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+#endif
+       
+       return g_ntohs(sin.sin_port);
+}
+
+static int udp_check_for_data(int sock)
+{
+       char buf[1025], **lines;
+       char *valptr;
+       gchar *title;
+       gint len, i;
+       struct sockaddr_in from;
+       socklen_t fromlen;
+
+       fromlen = sizeof(struct sockaddr_in);
+       
+       if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
+       {
+               if (errno != EAGAIN)
+               {
+                       g_log(NULL, G_LOG_LEVEL_CRITICAL,
+                             "udp_read_data(): Error reading from socket: %s", strerror(errno));
+                       return -1;
+               }
+               return 0;
+       }
+       buf[len] = '\0';
+#ifdef DEBUG_UDP
+       fprintf (stderr,"Received: [%s]\n", buf);
+#endif
+       lines = g_strsplit(buf, "\n", 0);
+       if (!lines)
+               return 0;
+       
+       for (i = 0; lines[i]; i++)
+       {
+               while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
+                      (lines[i][strlen(lines[i]) - 1] == '\r'))
+                       lines[i][strlen(lines[i]) - 1] = '\0';
+               
+               valptr = strchr(lines[i], ':');
+               
+               if (!valptr)
+                       continue;
+               else
+                       valptr++;
+               
+               g_strstrip(valptr);
+               if (!strlen(valptr))
+                       continue;
+               
+               if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
+               {
+                       title = g_strdup_printf ("%s (%s)", valptr, icy_name);
+                       if (going)
+                               set_track_info(title, -1);
+                       g_free (title);
+               }
+
+#if 0
+               else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
+               {
+                       if (atoi(valptr) != -1)
+                               set_track_info(NULL, atoi(valptr));
+               }
+#endif
+                               
+               else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
+               {
+                       /* set_track_info(title, -1); */
+/*                     xmms_show_message(_("Message"), valptr, _("Ok"), */
+/*                                       FALSE, NULL, NULL); */
+                       g_message("Stream_message: %s", valptr);
+               }
+
+#if 0
+               /* Use this to direct your webbrowser.. yeah right.. */
+               else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
+               {
+                       if (lasturl && g_strcmp (valptr, lasturl))
+                       {
+                               c_message (stderr, "Song URL: %s\n", valptr);
+                               g_free (lasturl);
+                               lasturl = g_strdup (valptr);
+                       }
+               }
+#endif
+               else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
+               {
+                       gchar obuf[60];
+                       sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr));
+                       if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
+                       {
+                               g_log(NULL, G_LOG_LEVEL_WARNING,
+                                     "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
+                       }
+#ifdef DEBUG_UDP
+                       else
+                               fprintf(stderr,"Sent ack: %s", obuf);
+                       fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
+#endif
+               }
+       }
+       g_strfreev(lines);
+       return 0;
+}
diff --git a/src/plugin_xmms/http.h b/src/plugin_xmms/http.h
new file mode 100644 (file)
index 0000000..0025430
--- /dev/null
@@ -0,0 +1,26 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ *
+ * 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__PLUGIN_XMMS__HTTP_H
+#define FLAC__PLUGIN_XMMS__HTTP_H
+
+extern int flac_http_open(const gchar * url, guint64 offset);
+extern void flac_http_close(void);
+extern int flac_http_read(gpointer data, gint length);
+
+
+#endif
diff --git a/src/plugin_xmms/locale_hack.h b/src/plugin_xmms/locale_hack.h
new file mode 100644 (file)
index 0000000..d04b1b2
--- /dev/null
@@ -0,0 +1,55 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2006,2007  Josh Coalson
+ *
+ * Based on:
+ * locale.h - 2000/05/05 13:10 Jerome Couderc
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kvè™±en <havardk@xmms.org>
+ *
+ * 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.
+ */
+/*
+ * Gettext support for EasyTAG
+ */
+
+
+#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+
+#include <locale.h>
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+#  include <libintl.h>
+#  define _(String) gettext (String)
+#  ifdef gettext_noop
+#    define N_(String) gettext_noop (String)
+#  else
+#    define N_(String) (String)
+#  endif
+#else
+#  define textdomain(String) (String)
+#  define gettext(String) (String)
+#  define dgettext(Domain,Message) (Message)
+#  define dcgettext(Domain,Message,Type) (Message)
+#  define bindtextdomain(Domain,Directory) (Domain)
+#  define _(String) (String)
+#  define N_(String) (String)
+#endif
+
+
+#endif
diff --git a/src/plugin_xmms/plugin.c b/src/plugin_xmms/plugin.c
new file mode 100644 (file)
index 0000000..24a79b7
--- /dev/null
@@ -0,0 +1,684 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <xmms/plugin.h>
+#include <xmms/util.h>
+#include <xmms/configfile.h>
+#include <xmms/titlestring.h>
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "FLAC/all.h"
+#include "plugin_common/all.h"
+#include "share/grabbag.h"
+#include "share/replaygain_synthesis.h"
+#include "configure.h"
+#include "charset.h"
+#include "http.h"
+#include "tag.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+extern void FLAC_XMMS__file_info_box(char *filename);
+
+typedef struct {
+       FLAC__bool abort_flag;
+       FLAC__bool is_playing;
+       FLAC__bool is_http_source;
+       FLAC__bool eof;
+       FLAC__bool play_thread_open; /* if true, is_playing must also be true */
+       FLAC__uint64 total_samples;
+       unsigned bits_per_sample;
+       unsigned channels;
+       unsigned sample_rate;
+       int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */
+       gchar *title;
+       AFormat sample_format;
+       unsigned sample_format_bytes_per_sample;
+       int seek_to_in_sec;
+       FLAC__bool has_replaygain;
+       double replay_scale;
+       DitherContext dither_context;
+} stream_data_struct;
+
+static void FLAC_XMMS__init(void);
+static int  FLAC_XMMS__is_our_file(char *filename);
+static void FLAC_XMMS__play_file(char *filename);
+static void FLAC_XMMS__stop(void);
+static void FLAC_XMMS__pause(short p);
+static void FLAC_XMMS__seek(int time);
+static int  FLAC_XMMS__get_time(void);
+static void FLAC_XMMS__cleanup(void);
+static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
+
+static void *play_loop_(void *arg);
+
+static FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder);
+static void safe_decoder_finish_(FLAC__StreamDecoder *decoder);
+static void safe_decoder_delete_(FLAC__StreamDecoder *decoder);
+
+static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, 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);
+
+InputPlugin flac_ip =
+{
+       NULL,
+       NULL,
+       "FLAC Player v" VERSION,
+       FLAC_XMMS__init,
+       FLAC_XMMS__aboutbox,
+       FLAC_XMMS__configure,
+       FLAC_XMMS__is_our_file,
+       NULL,
+       FLAC_XMMS__play_file,
+       FLAC_XMMS__stop,
+       FLAC_XMMS__pause,
+       FLAC_XMMS__seek,
+       NULL,
+       FLAC_XMMS__get_time,
+       NULL,
+       NULL,
+       FLAC_XMMS__cleanup,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       FLAC_XMMS__get_song_info,
+       FLAC_XMMS__file_info_box,
+       NULL
+};
+
+#define SAMPLES_PER_WRITE 512
+#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8))
+static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE];
+static unsigned sample_buffer_first_, sample_buffer_last_;
+
+static FLAC__StreamDecoder *decoder_ = 0;
+static stream_data_struct stream_data_;
+static pthread_t decode_thread_;
+static FLAC__bool audio_error_ = false;
+static FLAC__bool is_big_endian_host_;
+
+#define BITRATE_HIST_SEGMENT_MSEC 500
+/* 500ms * 50 = 25s should be enough */
+#define BITRATE_HIST_SIZE 50
+static unsigned bitrate_history_[BITRATE_HIST_SIZE];
+
+
+InputPlugin *get_iplugin_info(void)
+{
+       flac_ip.description = g_strdup_printf("Reference FLAC Player v%s", FLAC__VERSION_STRING);
+       return &flac_ip;
+}
+
+void set_track_info(const char* title, int length_in_msec)
+{
+       if (stream_data_.is_playing) {
+               flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+       }
+}
+
+static gchar* homedir(void)
+{
+       gchar *result;
+       char *env_home = getenv("HOME");
+       if (env_home) {
+               result = g_strdup (env_home);
+       } else {
+               uid_t uid = getuid();
+               struct passwd *pwent;
+               do {
+                       pwent = getpwent();
+               } while (pwent && pwent->pw_uid != uid);
+               result = pwent ? g_strdup (pwent->pw_dir) : NULL;
+               endpwent();
+       }
+       return result;
+}
+
+static FLAC__bool is_http_source(const char *source)
+{
+       return 0 == strncasecmp(source, "http://", 7);
+}
+
+void FLAC_XMMS__init(void)
+{
+       ConfigFile *cfg;
+       FLAC__uint32 test = 1;
+
+       is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+       flac_cfg.title.tag_override = FALSE;
+       if (flac_cfg.title.tag_format)
+               g_free(flac_cfg.title.tag_format);
+       flac_cfg.title.convert_char_set = FALSE;
+
+       cfg = xmms_cfg_open_default_file();
+
+       /* title */
+
+       xmms_cfg_read_boolean(cfg, "flac", "title.tag_override", &flac_cfg.title.tag_override);
+
+       if(!xmms_cfg_read_string(cfg, "flac", "title.tag_format", &flac_cfg.title.tag_format))
+               flac_cfg.title.tag_format = g_strdup("%p - %t");
+
+       xmms_cfg_read_boolean(cfg, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set);
+
+       if(!xmms_cfg_read_string(cfg, "flac", "title.user_char_set", &flac_cfg.title.user_char_set))
+               flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current();
+
+       /* replaygain */
+
+       xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable);
+
+       xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode);
+
+       if(!xmms_cfg_read_int(cfg, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp))
+               flac_cfg.output.replaygain.preamp = 0;
+
+       xmms_cfg_read_boolean(cfg, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit);
+
+       xmms_cfg_read_boolean(cfg, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16);
+       xmms_cfg_read_boolean(cfg, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither);
+
+       if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping))
+               flac_cfg.output.resolution.replaygain.noise_shaping = 1;
+
+       if(!xmms_cfg_read_int(cfg, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out))
+               flac_cfg.output.resolution.replaygain.bps_out = 16;
+
+       /* stream */
+
+       xmms_cfg_read_int(cfg, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size);
+       xmms_cfg_read_int(cfg, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer);
+       xmms_cfg_read_boolean(cfg, "flac", "stream.use_proxy", &flac_cfg.stream.use_proxy);
+       if(flac_cfg.stream.proxy_host)
+               g_free(flac_cfg.stream.proxy_host);
+       if(!xmms_cfg_read_string(cfg, "flac", "stream.proxy_host", &flac_cfg.stream.proxy_host))
+               flac_cfg.stream.proxy_host = g_strdup("");
+       xmms_cfg_read_int(cfg, "flac", "stream.proxy_port", &flac_cfg.stream.proxy_port);
+       xmms_cfg_read_boolean(cfg, "flac", "stream.proxy_use_auth", &flac_cfg.stream.proxy_use_auth);
+       if(flac_cfg.stream.proxy_user)
+               g_free(flac_cfg.stream.proxy_user);
+       flac_cfg.stream.proxy_user = NULL;
+       xmms_cfg_read_string(cfg, "flac", "stream.proxy_user", &flac_cfg.stream.proxy_user);
+       if(flac_cfg.stream.proxy_pass)
+               g_free(flac_cfg.stream.proxy_pass);
+       flac_cfg.stream.proxy_pass = NULL;
+       xmms_cfg_read_string(cfg, "flac", "stream.proxy_pass", &flac_cfg.stream.proxy_pass);
+       xmms_cfg_read_boolean(cfg, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream);
+       if (flac_cfg.stream.save_http_path)
+               g_free (flac_cfg.stream.save_http_path);
+       if (!xmms_cfg_read_string(cfg, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) || ! *flac_cfg.stream.save_http_path) {
+               if (flac_cfg.stream.save_http_path)
+                       g_free (flac_cfg.stream.save_http_path);
+               flac_cfg.stream.save_http_path = homedir();
+       }
+       xmms_cfg_read_boolean(cfg, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming);
+       xmms_cfg_read_boolean(cfg, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel);
+
+       decoder_ = FLAC__stream_decoder_new();
+
+       xmms_cfg_free(cfg);
+}
+
+int FLAC_XMMS__is_our_file(char *filename)
+{
+       char *ext;
+
+       ext = strrchr(filename, '.');
+       if(ext)
+               if(!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla"))
+                       return 1;
+       return 0;
+}
+
+void FLAC_XMMS__play_file(char *filename)
+{
+       FILE *f;
+
+       sample_buffer_first_ = sample_buffer_last_ = 0;
+       audio_error_ = false;
+       stream_data_.abort_flag = false;
+       stream_data_.is_playing = false;
+       stream_data_.is_http_source = is_http_source(filename);
+       stream_data_.eof = false;
+       stream_data_.play_thread_open = false;
+       stream_data_.has_replaygain = false;
+
+       if(!is_http_source(filename)) {
+               if(0 == (f = fopen(filename, "r")))
+                       return;
+               fclose(f);
+       }
+
+       if(decoder_ == 0)
+               return;
+
+       if(!safe_decoder_init_(filename, decoder_))
+               return;
+
+       if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) {
+               if(flac_cfg.output.resolution.replaygain.bps_out == 8) {
+                       stream_data_.sample_format = FMT_U8;
+                       stream_data_.sample_format_bytes_per_sample = 1;
+               }
+               else if(flac_cfg.output.resolution.replaygain.bps_out == 16) {
+                       stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+                       stream_data_.sample_format_bytes_per_sample = 2;
+               }
+               else {
+                       /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+                       fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out);
+                       safe_decoder_finish_(decoder_);
+                       return;
+               }
+       }
+       else {
+               if(stream_data_.bits_per_sample == 8) {
+                       stream_data_.sample_format = FMT_U8;
+                       stream_data_.sample_format_bytes_per_sample = 1;
+               }
+               else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) {
+                       stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+                       stream_data_.sample_format_bytes_per_sample = 2;
+               }
+               else {
+                       /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+                       fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", stream_data_.bits_per_sample);
+                       safe_decoder_finish_(decoder_);
+                       return;
+               }
+       }
+       FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping);
+       stream_data_.is_playing = true;
+
+       if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) {
+               audio_error_ = true;
+               safe_decoder_finish_(decoder_);
+               return;
+       }
+
+       stream_data_.title = flac_format_song_title(filename);
+       flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+
+       stream_data_.seek_to_in_sec = -1;
+       stream_data_.play_thread_open = true;
+       pthread_create(&decode_thread_, NULL, play_loop_, NULL);
+}
+
+void FLAC_XMMS__stop(void)
+{
+       if(stream_data_.is_playing) {
+               stream_data_.is_playing = false;
+               if(stream_data_.play_thread_open) {
+                       stream_data_.play_thread_open = false;
+                       pthread_join(decode_thread_, NULL);
+               }
+               flac_ip.output->close_audio();
+               safe_decoder_finish_(decoder_);
+       }
+}
+
+void FLAC_XMMS__pause(short p)
+{
+       flac_ip.output->pause(p);
+}
+
+void FLAC_XMMS__seek(int time)
+{
+       if(!stream_data_.is_http_source) {
+               stream_data_.seek_to_in_sec = time;
+               stream_data_.eof = false;
+
+               while(stream_data_.seek_to_in_sec != -1)
+                       xmms_usleep(10000);
+       }
+}
+
+int FLAC_XMMS__get_time(void)
+{
+       if(audio_error_)
+               return -2;
+       if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing()))
+               return -1;
+       else
+               return flac_ip.output->output_time();
+}
+
+void FLAC_XMMS__cleanup(void)
+{
+       safe_decoder_delete_(decoder_);
+       decoder_ = 0;
+}
+
+void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
+{
+       FLAC__StreamMetadata streaminfo;
+
+       if(0 == filename)
+               filename = "";
+
+       if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
+               /* @@@ how to report the error? */
+               if(title) {
+                       if (!is_http_source(filename)) {
+                               static const char *errtitle = "Invalid FLAC File: ";
+                               if(strlen(errtitle) + 1 + strlen(filename) + 1 + 1 < strlen(filename)) { /* overflow check */
+                                       *title = NULL;
+                               }
+                               else {
+                                       *title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1);
+                                       sprintf(*title, "%s\"%s\"", errtitle, filename);
+                               }
+                       } else {
+                               *title = NULL;
+                       }
+               }
+               if(length_in_msec)
+                       *length_in_msec = -1;
+               return;
+       }
+
+       if(title) {
+               *title = flac_format_song_title(filename);
+       }
+       if(length_in_msec) {
+               FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
+               if (l > INT_MAX)
+                       l = INT_MAX;
+               *length_in_msec = (int)l;
+       }
+}
+
+/***********************************************************************
+ * local routines
+ **********************************************************************/
+
+void *play_loop_(void *arg)
+{
+       unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1;
+       FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0;
+
+       (void)arg;
+
+       while(stream_data_.is_playing) {
+               if(!stream_data_.eof) {
+                       while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) {
+                               unsigned s;
+
+                               s = sample_buffer_last_ - sample_buffer_first_;
+                               if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) {
+                                       stream_data_.eof = true;
+                                       break;
+                               }
+                               else if(!FLAC__stream_decoder_process_single(decoder_)) {
+                                       /*@@@ this should probably be a dialog */
+                                       fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n");
+                                       stream_data_.eof = true;
+                                       break;
+                               }
+                               blocksize = sample_buffer_last_ - sample_buffer_first_ - s;
+                               decode_position_frame_last = decode_position_frame;
+                               if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+                                       decode_position_frame = 0;
+                       }
+                       if(sample_buffer_last_ - sample_buffer_first_ > 0) {
+                               const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE);
+                               int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+                               FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+                               unsigned written_time, bh_index_w;
+                               FLAC__uint64 decode_position;
+
+                               sample_buffer_first_ += n;
+                               flac_ip.add_vis_pcm(flac_ip.output->written_time(), stream_data_.sample_format, stream_data_.channels, bytes, sample_buffer_start);
+                               while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+                                       xmms_usleep(10000);
+                               if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+                                       flac_ip.output->write_audio(sample_buffer_start, bytes);
+
+                               /* compute current bitrate */
+
+                               written_time = flac_ip.output->written_time();
+                               bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+                               if(bh_index_w != bh_index_last_w) {
+                                       bh_index_last_w = bh_index_w;
+                                       decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize;
+                                       bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] =
+                                               decode_position > decode_position_last && written_time > written_time_last ?
+                                                       8000 * (decode_position - decode_position_last) / (written_time - written_time_last) :
+                                                       stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample;
+                                       decode_position_last = decode_position;
+                                       written_time_last = written_time;
+                               }
+                       }
+                       else {
+                               stream_data_.eof = true;
+                               xmms_usleep(10000);
+                       }
+               }
+               else
+                       xmms_usleep(10000);
+               if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) {
+                       const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec;
+                       FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples);
+                       if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples)
+                               target_sample = stream_data_.total_samples - 1;
+                       if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) {
+                               flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000);
+                               bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+                               if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+                                       decode_position_frame = 0;
+                               stream_data_.eof = false;
+                               sample_buffer_first_ = sample_buffer_last_ = 0;
+                       }
+                       else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) {
+                               /*@@@ this should probably be a dialog */
+                               fprintf(stderr, "libxmms-flac: SEEK ERROR\n");
+                               FLAC__stream_decoder_flush(decoder_);
+                               stream_data_.eof = false;
+                               sample_buffer_first_ = sample_buffer_last_ = 0;
+                       }
+                       stream_data_.seek_to_in_sec = -1;
+               }
+               else {
+                       /* display the right bitrate from history */
+                       unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+                       if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) {
+                               bh_index_last_o = bh_index_o;
+                               flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels);
+                       }
+               }
+       }
+
+       safe_decoder_finish_(decoder_);
+
+       /* are these two calls necessary? */
+       flac_ip.output->buffer_free();
+       flac_ip.output->buffer_free();
+
+       g_free(stream_data_.title);
+
+       pthread_exit(NULL);
+       return 0; /* to silence the compiler warning about not returning a value */
+}
+
+FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder)
+{
+       if(decoder == 0)
+               return false;
+
+       safe_decoder_finish_(decoder);
+
+       FLAC__stream_decoder_set_md5_checking(decoder, false);
+       FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+       FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+       FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       if(stream_data_.is_http_source) {
+               flac_http_open(filename, 0);
+               if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+                       return false;
+       }
+       else {
+               if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+                       return false;
+       }
+
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+               return false;
+
+       return true;
+}
+
+void safe_decoder_finish_(FLAC__StreamDecoder *decoder)
+{
+       if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED)
+               (void)FLAC__stream_decoder_finish(decoder);
+       if(stream_data_.is_http_source)
+               flac_http_close();
+}
+
+void safe_decoder_delete_(FLAC__StreamDecoder *decoder)
+{
+       if(decoder) {
+               safe_decoder_finish_(decoder);
+               FLAC__stream_decoder_delete(decoder);
+       }
+}
+
+FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       (void)decoder;
+       (void)client_data;
+       *bytes = flac_http_read(buffer, *bytes);
+       return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       stream_data_struct *stream_data = (stream_data_struct *)client_data;
+       const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize;
+       const unsigned bits_per_sample = stream_data->bits_per_sample;
+       FLAC__byte *sample_buffer_start;
+
+       (void)decoder;
+
+       if(stream_data->abort_flag)
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+       if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) {
+               memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample);
+               sample_buffer_last_ -= sample_buffer_first_;
+               sample_buffer_first_ = 0;
+       }
+       sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample;
+       if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) {
+               FLAC__replaygain_synthesis__apply_gain(
+                               sample_buffer_start,
+                               !is_big_endian_host_,
+                               stream_data->sample_format_bytes_per_sample == 1, /* unsigned_data_out */
+                               buffer,
+                               wide_samples,
+                               channels,
+                               bits_per_sample,
+                               stream_data->sample_format_bytes_per_sample * 8,
+                               stream_data->replay_scale,
+                               flac_cfg.output.replaygain.hard_limit,
+                               flac_cfg.output.resolution.replaygain.dither,
+                               &stream_data->dither_context
+               );
+       }
+       else if(is_big_endian_host_) {
+               FLAC__plugin_common__pack_pcm_signed_big_endian(
+                       sample_buffer_start,
+                       buffer,
+                       wide_samples,
+                       channels,
+                       bits_per_sample,
+                       stream_data->sample_format_bytes_per_sample * 8
+               );
+       }
+       else {
+               FLAC__plugin_common__pack_pcm_signed_little_endian(
+                       sample_buffer_start,
+                       buffer,
+                       wide_samples,
+                       channels,
+                       bits_per_sample,
+                       stream_data->sample_format_bytes_per_sample * 8
+               );
+       }
+
+       sample_buffer_last_ += wide_samples;
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       stream_data_struct *stream_data = (stream_data_struct *)client_data;
+       (void)decoder;
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               stream_data->total_samples = metadata->data.stream_info.total_samples;
+               stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+               stream_data->channels = metadata->data.stream_info.channels;
+               stream_data->sample_rate = metadata->data.stream_info.sample_rate;
+               {
+                       FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5);
+                       if (l > INT_MAX)
+                               l = INT_MAX;
+                       stream_data->length_in_msec = (int)l;
+               }
+       }
+       else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+               double reference, gain, peak;
+               if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) {
+                       stream_data->has_replaygain = true;
+                       stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit);
+               }
+       }
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       stream_data_struct *stream_data = (stream_data_struct *)client_data;
+       (void)decoder;
+       if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+               stream_data->abort_flag = true;
+}
diff --git a/src/plugin_xmms/plugin.h b/src/plugin_xmms/plugin.h
new file mode 100644 (file)
index 0000000..334c167
--- /dev/null
@@ -0,0 +1,24 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2004,2005,2006,2007  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__PLUGIN_XMMS__PLUGIN_H
+#define FLAC__PLUGIN_XMMS__PLUGIN_H
+
+void set_track_info(const char* title, int length_in_msec);
+
+#endif
diff --git a/src/plugin_xmms/tag.c b/src/plugin_xmms/tag.c
new file mode 100644 (file)
index 0000000..c4a7c94
--- /dev/null
@@ -0,0 +1,154 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Daisuke Shimamura
+ *
+ * Based on FLAC plugin.c and mpg123 plugin
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <xmms/plugin.h>
+#include <xmms/util.h>
+#include <xmms/configfile.h>
+#include <xmms/titlestring.h>
+
+#include "FLAC/metadata.h"
+#include "plugin_common/tags.h"
+#include "charset.h"
+#include "configure.h"
+
+/*
+ * Function local__extname (filename)
+ *
+ *    Return pointer within filename to its extenstion, or NULL if
+ *    filename has no extension.
+ *
+ */
+static char *local__extname(const char *filename)
+{
+       char *ext = strrchr(filename, '.');
+
+       if (ext != NULL)
+               ++ext;
+
+       return ext;
+}
+
+static char *local__getstr(char* str)
+{
+       if (str && strlen(str) > 0)
+               return str;
+       return NULL;
+}
+
+static int local__getnum(char* str)
+{
+       if (str && strlen(str) > 0)
+               return atoi(str);
+       return 0;
+}
+
+static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name)
+{
+       if (0 != tags) {
+               const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+               if (0 != utf8) {
+                       if(flac_cfg.title.convert_char_set)
+                               return convert_from_utf8_to_user(utf8);
+                       else
+                               return strdup(utf8);
+               }
+       }
+
+       return 0;
+}
+
+static void local__safe_free(char *s)
+{
+       if (0 != s)
+               free(s);
+}
+
+/*
+ * Function flac_format_song_title (tag, filename)
+ *
+ *    Create song title according to `tag' and/or `filename' and
+ *    return it.  The title must be subsequently freed using g_free().
+ *
+ */
+char *flac_format_song_title(char *filename)
+{
+       char *ret = NULL;
+       TitleInput *input = NULL;
+       FLAC__StreamMetadata *tags;
+       char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description;
+
+       FLAC_plugin__tags_get(filename, &tags);
+
+       title       = local__getfield(tags, "TITLE");
+       artist      = local__getfield(tags, "ARTIST");
+       performer   = local__getfield(tags, "PERFORMER");
+       album       = local__getfield(tags, "ALBUM");
+       date        = local__getfield(tags, "DATE");
+       tracknumber = local__getfield(tags, "TRACKNUMBER");
+       genre       = local__getfield(tags, "GENRE");
+       description = local__getfield(tags, "DESCRIPTION");
+
+       XMMS_NEW_TITLEINPUT(input);
+
+       input->performer = local__getstr(performer);
+       if(!input->performer)
+               input->performer = local__getstr(artist);
+       input->album_name = local__getstr(album);
+       input->track_name = local__getstr(title);
+       input->track_number = local__getnum(tracknumber);
+       input->year = local__getnum(date);
+       input->genre = local__getstr(genre);
+       input->comment = local__getstr(description);
+
+       input->file_name = g_basename(filename);
+       input->file_path = filename;
+       input->file_ext = local__extname(filename);
+       ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), input);
+       g_free(input);
+
+       if (!ret) {
+               /*
+                * Format according to filename.
+                */
+               ret = g_strdup(g_basename(filename));
+               if (local__extname(ret) != NULL)
+                       *(local__extname(ret) - 1) = '\0';      /* removes period */
+       }
+
+       FLAC_plugin__tags_destroy(&tags);
+       local__safe_free(title);
+       local__safe_free(artist);
+       local__safe_free(performer);
+       local__safe_free(album);
+       local__safe_free(date);
+       local__safe_free(tracknumber);
+       local__safe_free(genre);
+       local__safe_free(description);
+       return ret;
+}
diff --git a/src/plugin_xmms/tag.h b/src/plugin_xmms/tag.h
new file mode 100644 (file)
index 0000000..d952fbc
--- /dev/null
@@ -0,0 +1,24 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ * 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__PLUGIN_XMMS__TAG_H
+#define FLAC__PLUGIN_XMMS__TAG_H
+
+gchar *flac_format_song_title(gchar * filename);
+
+#endif
diff --git a/src/share/Makefile.am b/src/share/Makefile.am
new file mode 100644 (file)
index 0000000..19d71ee
--- /dev/null
@@ -0,0 +1,22 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = getopt replaygain_analysis replaygain_synthesis grabbag utf8
+
+EXTRA_DIST = \
+       Makefile.lite \
+       README
diff --git a/src/share/Makefile.lite b/src/share/Makefile.lite
new file mode 100644 (file)
index 0000000..9ed2198
--- /dev/null
@@ -0,0 +1,53 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+.PHONY: all getopt grabbag replaygain_analysis replaygain_synthesis utf8
+all: getopt grabbag replaygain_analysis replaygain_synthesis utf8
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+getopt:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+grabbag:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+replaygain_analysis:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+replaygain_synthesis:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+utf8:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+       -(cd getopt ; $(MAKE) -f Makefile.lite clean)
+       -(cd grabbag ; $(MAKE) -f Makefile.lite clean)
+       -(cd replaygain_analysis ; $(MAKE) -f Makefile.lite clean)
+       -(cd replaygain_synthesis ; $(MAKE) -f Makefile.lite clean)
+       -(cd utf8 ; $(MAKE) -f Makefile.lite clean)
diff --git a/src/share/README b/src/share/README
new file mode 100644 (file)
index 0000000..1d4fede
--- /dev/null
@@ -0,0 +1,5 @@
+This directory contains several convenience libraries used by the rest of the
+tools and plugins.  Two of them (getopt and utf8) are shamelessly copied from
+vorbistools, one for manipulating UTF-8 strings (GPL) and one for implementing
+getopt (LGPL).  libFLAC does not link to either; the only FLAC tools that do
+are GPL'ed.
diff --git a/src/share/getopt/Makefile.am b/src/share/getopt/Makefile.am
new file mode 100644 (file)
index 0000000..f40464e
--- /dev/null
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/include/share
+
+noinst_LIBRARIES = libgetopt.a
+
+libgetopt_a_SOURCES = getopt.c getopt1.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       getopt_static.dsp \
+       getopt_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/share/getopt/Makefile.lite b/src/share/getopt/Makefile.lite
new file mode 100644 (file)
index 0000000..e36f341
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libgetopt
+INCLUDES = -I$(topdir)/include -I$(topdir)/include/share
+
+SRCS_C = \
+       getopt.c \
+       getopt1.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/getopt/getopt.c b/src/share/getopt/getopt.c
new file mode 100644 (file)
index 0000000..279dff0
--- /dev/null
@@ -0,0 +1,1065 @@
+/*
+       NOTE:
+       I cannot get the vanilla getopt code to work (i.e. compile only what
+       is needed and not duplicate symbols found in the standard library)
+       on all the platforms that FLAC supports.  In particular the gating
+       of code with the ELIDE_CODE #define is not accurate enough on systems
+       that are POSIX but not glibc.  If someone has a patch that works on
+       GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+               http://sourceforge.net/projects/flac
+
+       In the meantime I have munged the global symbols and removed gates
+       around code, while at the same time trying to touch the original as
+       little as possible.
+*/
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper@gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+       Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)     gettext (msgid)
+# else
+#  define _(msgid)     (msgid)
+# endif
+#endif
+
+/* This version of `share__getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `share__getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+/* For communication from `share__getopt' to the caller.
+   When `share__getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *share__optarg = 0; /*[JEC] initialize to avoid being a 'Common' symbol */
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `share__getopt'.
+
+   On entry to `share__getopt', zero means this is the first call; initialize.
+
+   When `share__getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `share__optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int share__optind = 1;
+
+/* Formerly, initialization of getopt depended on share__optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+static int share____getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int share__opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int share__optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `share__getopt' to return -1 with `share__optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index      strchr
+#else
+
+#include <string.h>
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)                                               \
+    {                                                                        \
+      char __tmp = __getopt_nonoption_flags[ch1];                            \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];         \
+      __getopt_nonoption_flags[ch2] = __tmp;                                 \
+    }
+#else  /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,share__optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = share__optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+        presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+       nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+       {
+         memset (__mempcpy (new_str, __getopt_nonoption_flags,
+                            nonoption_flags_max_len),
+                 '\0', top + 1 - nonoption_flags_max_len);
+         nonoption_flags_max_len = top + 1;
+         __getopt_nonoption_flags = new_str;
+       }
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+             SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+             SWAP_FLAGS (bottom + i, middle + i);
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (share__optind - last_nonopt);
+  last_nonopt = share__optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *share___getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+share___getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = share__optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+       {
+         if (__getopt_nonoption_flags == NULL
+             || __getopt_nonoption_flags[0] == '\0')
+           nonoption_flags_max_len = -1;
+         else
+           {
+             const char *orig_str = __getopt_nonoption_flags;
+             int len = nonoption_flags_max_len = strlen (orig_str);
+             if (nonoption_flags_max_len < argc)
+               nonoption_flags_max_len = argc;
+             __getopt_nonoption_flags =
+               (char *) malloc (nonoption_flags_max_len);
+             if (__getopt_nonoption_flags == NULL)
+               nonoption_flags_max_len = -1;
+             else
+               memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+                       '\0', nonoption_flags_max_len - len);
+           }
+       }
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#else
+  (void)argc, (void)argv;
+#endif
+
+  return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `share__getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `share__getopt' finds another option character, it returns that character,
+   updating `share__optind' and `nextchar' so that the next call to `share__getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `share__getopt' returns -1.
+   Then `share__optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `share__opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `share__optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `share__optarg', otherwise `share__optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `share__getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct share__option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+share___getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct share__option *longopts;
+     int *longind;
+     int long_only;
+{
+  share__optarg = NULL;
+
+  if (share__optind == 0 || !share____getopt_initialized)
+    {
+      if (share__optind == 0)
+       share__optind = 1;      /* Don't scan ARGV[0], the program name.  */
+      optstring = share___getopt_initialize (argc, argv, optstring);
+      share____getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[share__optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0'        \
+                     || (share__optind < nonoption_flags_len                         \
+                         && __getopt_nonoption_flags[share__optind] == '1'))
+#else
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+        moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > share__optind)
+       last_nonopt = share__optind;
+      if (first_nonopt > share__optind)
+       first_nonopt = share__optind;
+
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != share__optind)
+           first_nonopt = share__optind;
+
+         /* Skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (share__optind < argc && NONOPTION_P)
+           share__optind++;
+         last_nonopt = share__optind;
+       }
+
+      /* The special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (share__optind != argc && !strcmp (argv[share__optind], "--"))
+       {
+         share__optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = share__optind;
+         last_nonopt = argc;
+
+         share__optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (share__optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           share__optind = first_nonopt;
+         return -1;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+       {
+         if (ordering == REQUIRE_ORDER)
+           return -1;
+         share__optarg = argv[share__optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Skip the initial punctuation.  */
+
+      nextchar = (argv[share__optind] + 1
+                 + (longopts != NULL && argv[share__optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[share__optind][1] == '-'
+         || (long_only && (argv[share__optind][2] || !my_index (optstring, argv[share__optind][1])))))
+    {
+      char *nameend;
+      const struct share__option *p;
+      const struct share__option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+       /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+        or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+       if (!strncmp (p->name, nextchar, nameend - nextchar))
+         {
+           if ((unsigned int) (nameend - nextchar)
+               == (unsigned int) strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second or later nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (share__opterr)
+           fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+                    argv[0], argv[share__optind]);
+         nextchar += strlen (nextchar);
+         share__optind++;
+         share__optopt = 0;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         share__optind++;
+         if (*nameend)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               share__optarg = nameend + 1;
+             else
+               {
+                 if (share__opterr)
+                   {
+                     if (argv[share__optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                _("%s: option `--%s' doesn't allow an argument\n"),
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                                _("%s: option `%c%s' doesn't allow an argument\n"),
+                                argv[0], argv[share__optind - 1][0], pfound->name);
+                   }
+
+                 nextchar += strlen (nextchar);
+
+                 share__optopt = pfound->val;
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (share__optind < argc)
+               share__optarg = argv[share__optind++];
+             else
+               {
+                 if (share__opterr)
+                   fprintf (stderr,
+                          _("%s: option `%s' requires an argument\n"),
+                          argv[0], argv[share__optind - 1]);
+                 nextchar += strlen (nextchar);
+                 share__optopt = pfound->val;
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+
+      /* Can't find it as a long option.  If this is not share__getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[share__optind][1] == '-'
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (share__opterr)
+           {
+             if (argv[share__optind][1] == '-')
+               /* --option */
+               fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+                        argv[0], argv[share__optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         share__optind++;
+         share__optopt = 0;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `share__optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++share__optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (share__opterr)
+         {
+           if (posixly_correct)
+             /* 1003.2 specifies the format of this message.  */
+             fprintf (stderr, _("%s: illegal option -- %c\n"),
+                      argv[0], c);
+           else
+             fprintf (stderr, _("%s: invalid option -- %c\n"),
+                      argv[0], c);
+         }
+       share__optopt = c;
+       return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+       char *nameend;
+       const struct share__option *p;
+       const struct share__option *pfound = NULL;
+       int exact = 0;
+       int ambig = 0;
+       int indfound = 0;
+       int option_index;
+
+       /* This is an option that requires an argument.  */
+       if (*nextchar != '\0')
+         {
+           share__optarg = nextchar;
+           /* If we end this ARGV-element by taking the rest as an arg,
+              we must advance to the next element now.  */
+           share__optind++;
+         }
+       else if (share__optind == argc)
+         {
+           if (share__opterr)
+             {
+               /* 1003.2 specifies the format of this message.  */
+               fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+                        argv[0], c);
+             }
+           share__optopt = c;
+           if (optstring[0] == ':')
+             c = ':';
+           else
+             c = '?';
+           return c;
+         }
+       else
+         /* We already incremented `share__optind' once;
+            increment it again when taking next ARGV-elt as argument.  */
+         share__optarg = argv[share__optind++];
+
+       /* share__optarg is now the argument, see if it's in the
+          table of longopts.  */
+
+       for (nextchar = nameend = share__optarg; *nameend && *nameend != '='; nameend++)
+         /* Do nothing.  */ ;
+
+       /* Test all long options for either exact match
+          or abbreviated matches.  */
+       for (p = longopts, option_index = 0; p->name; p++, option_index++)
+         if (!strncmp (p->name, nextchar, nameend - nextchar))
+           {
+             if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+               {
+                 /* Exact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+                 exact = 1;
+                 break;
+               }
+             else if (pfound == NULL)
+               {
+                 /* First nonexact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+               }
+             else
+               /* Second or later nonexact match found.  */
+               ambig = 1;
+           }
+       if (ambig && !exact)
+         {
+           if (share__opterr)
+             fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+                      argv[0], argv[share__optind]);
+           nextchar += strlen (nextchar);
+           share__optind++;
+           return '?';
+         }
+       if (pfound != NULL)
+         {
+           option_index = indfound;
+           if (*nameend)
+             {
+               /* Don't test has_arg with >, because some C compilers don't
+                  allow it to be used on enums.  */
+               if (pfound->has_arg)
+                 share__optarg = nameend + 1;
+               else
+                 {
+                   if (share__opterr)
+                     fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+                              argv[0], pfound->name);
+
+                   nextchar += strlen (nextchar);
+                   return '?';
+                 }
+             }
+           else if (pfound->has_arg == 1)
+             {
+               if (share__optind < argc)
+                 share__optarg = argv[share__optind++];
+               else
+                 {
+                   if (share__opterr)
+                     fprintf (stderr,
+                              _("%s: option `%s' requires an argument\n"),
+                              argv[0], argv[share__optind - 1]);
+                   nextchar += strlen (nextchar);
+                   return optstring[0] == ':' ? ':' : '?';
+                 }
+             }
+           nextchar += strlen (nextchar);
+           if (longind != NULL)
+             *longind = option_index;
+           if (pfound->flag)
+             {
+               *(pfound->flag) = pfound->val;
+               return 0;
+             }
+           return pfound->val;
+         }
+         nextchar = NULL;
+         return 'W';   /* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               share__optarg = nextchar;
+               share__optind++;
+             }
+           else
+             share__optarg = NULL;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               share__optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               share__optind++;
+             }
+           else if (share__optind == argc)
+             {
+               if (share__opterr)
+                 {
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr,
+                          _("%s: option requires an argument -- %c\n"),
+                          argv[0], c);
+                 }
+               share__optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `share__optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             share__optarg = argv[share__optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+share__getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return share___getopt_internal (argc, argv, optstring,
+                          (const struct share__option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `share__getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = share__optind ? share__optind : 1;
+
+      c = share__getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", share__optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (share__optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (share__optind < argc)
+       printf ("%s ", argv[share__optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/share/getopt/getopt1.c b/src/share/getopt/getopt1.c
new file mode 100644 (file)
index 0000000..1e57486
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+       NOTE:
+       I cannot get the vanilla getopt code to work (i.e. compile only what
+       is needed and not duplicate symbols found in the standard library)
+       on all the platforms that FLAC supports.  In particular the gating
+       of code with the ELIDE_CODE #define is not accurate enough on systems
+       that are POSIX but not glibc.  If someone has a patch that works on
+       GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+               http://sourceforge.net/projects/flac
+
+       In the meantime I have munged the global symbols and removed gates
+       around code, while at the same time trying to touch the original as
+       little as possible.
+*/
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+     Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+\f
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+share__getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct share__option *long_options;
+     int *opt_index;
+{
+  return share___getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like share__getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+share__getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct share__option *long_options;
+     int *opt_index;
+{
+  return share___getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = share__optind ? share__optind : 1;
+      int option_index = 0;
+      static struct share__option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = share__getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (share__optarg)
+           printf (" with arg %s", share__optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", share__optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", share__optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (share__optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (share__optind < argc)
+       printf ("%s ", argv[share__optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/share/getopt/getopt_static.dsp b/src/share/getopt/getopt_static.dsp
new file mode 100644 (file)
index 0000000..5db7bf0
--- /dev/null
@@ -0,0 +1,112 @@
+# Microsoft Developer Studio Project File - Name="getopt_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=getopt_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "getopt_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "getopt_static.mak" CFG="getopt_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "getopt_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "getopt_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "getopt"\r
+# PROP Scc_LocalPath "..\..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "getopt_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I ".\include" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "getopt_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "getopt_static - Win32 Release"\r
+# Name "getopt_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\getopt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\getopt1.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\getopt.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/share/getopt/getopt_static.vcproj b/src/share/getopt/getopt_static.vcproj
new file mode 100644 (file)
index 0000000..f60167d
--- /dev/null
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="getopt_static"\r
+       ProjectGUID="{4cefbc80-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="getopt_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\getopt.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\getopt1.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\include\share\getopt.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/share/grabbag/Makefile.am b/src/share/grabbag/Makefile.am
new file mode 100644 (file)
index 0000000..879b155
--- /dev/null
@@ -0,0 +1,25 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libgrabbag.la
+
+libgrabbag_la_SOURCES = \
+       cuesheet.c \
+       file.c \
+       picture.c \
+       replaygain.c \
+       seektable.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       grabbag_static.dsp \
+       grabbag_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/share/grabbag/Makefile.lite b/src/share/grabbag/Makefile.lite
new file mode 100644 (file)
index 0000000..daf1975
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libgrabbag
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+       cuesheet.c \
+       file.c \
+       picture.c \
+       replaygain.c \
+       seektable.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/grabbag/cuesheet.c b/src/share/grabbag/cuesheet.c
new file mode 100644 (file)
index 0000000..03f7cda
--- /dev/null
@@ -0,0 +1,611 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames)
+{
+       return ((minutes * 60) + seconds) * 75 + frames;
+}
+
+void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames)
+{
+       *frames = frame % 75;
+       frame /= 75;
+       *seconds = frame % 60;
+       frame /= 60;
+       *minutes = frame;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static int local__parse_int_(const char *s)
+{
+       int ret = 0;
+       char c;
+
+       if(*s == '\0')
+               return -1;
+
+       while('\0' != (c = *s++))
+               if(c >= '0' && c <= '9')
+                       ret = ret * 10 + (c - '0');
+               else
+                       return -1;
+
+       return ret;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static FLAC__int64 local__parse_int64_(const char *s)
+{
+       FLAC__int64 ret = 0;
+       char c;
+
+       if(*s == '\0')
+               return -1;
+
+       while('\0' != (c = *s++))
+               if(c >= '0' && c <= '9')
+                       ret = ret * 10 + (c - '0');
+               else
+                       return -1;
+
+       return ret;
+}
+
+/* accept '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67
+ * return sample number or <0 for error
+ */
+static FLAC__int64 local__parse_msf_(const char *s)
+{
+       FLAC__int64 ret, field;
+       char c;
+
+       c = *s++;
+       if(c >= '0' && c <= '9')
+               field = (c - '0');
+       else
+               return -1;
+       while(':' != (c = *s++)) {
+               if(c >= '0' && c <= '9')
+                       field = field * 10 + (c - '0');
+               else
+                       return -1;
+       }
+
+       ret = field * 60 * 44100;
+
+       c = *s++;
+       if(c >= '0' && c <= '9')
+               field = (c - '0');
+       else
+               return -1;
+       if(':' != (c = *s++)) {
+               if(c >= '0' && c <= '9') {
+                       field = field * 10 + (c - '0');
+                       c = *s++;
+                       if(c != ':')
+                               return -1;
+               }
+               else
+                       return -1;
+       }
+
+       if(field >= 60)
+               return -1;
+
+       ret += field * 44100;
+
+       c = *s++;
+       if(c >= '0' && c <= '9')
+               field = (c - '0');
+       else
+               return -1;
+       if('\0' != (c = *s++)) {
+               if(c >= '0' && c <= '9') {
+                       field = field * 10 + (c - '0');
+                       c = *s++;
+               }
+               else
+                       return -1;
+       }
+
+       if(c != '\0')
+               return -1;
+
+       if(field >= 75)
+               return -1;
+
+       ret += field * (44100 / 75);
+
+       return ret;
+}
+
+static char *local__get_field_(char **s, FLAC__bool allow_quotes)
+{
+       FLAC__bool has_quote = false;
+       char *p;
+
+       FLAC__ASSERT(0 != s);
+
+       if(0 == *s)
+               return 0;
+
+       /* skip leading whitespace */
+       while(**s && 0 != strchr(" \t\r\n", **s))
+               (*s)++;
+
+       if(**s == 0) {
+               *s = 0;
+               return 0;
+       }
+
+       if(allow_quotes && (**s == '"')) {
+               has_quote = true;
+               (*s)++;
+               if(**s == 0) {
+                       *s = 0;
+                       return 0;
+               }
+       }
+
+       p = *s;
+
+       if(has_quote) {
+               *s = strchr(*s, '\"');
+               /* if there is no matching end quote, it's an error */
+               if(0 == *s)
+                       p = *s = 0;
+               else {
+                       **s = '\0';
+                       (*s)++;
+               }
+       }
+       else {
+               while(**s && 0 == strchr(" \t\r\n", **s))
+                       (*s)++;
+               if(**s) {
+                       **s = '\0';
+                       (*s)++;
+               }
+               else
+                       *s = 0;
+       }
+
+       return p;
+}
+
+static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__StreamMetadata *cuesheet, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+#define FLAC__STRCASECMP stricmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#endif
+       char buffer[4096], *line, *field;
+       unsigned forced_leadout_track_num = 0;
+       FLAC__uint64 forced_leadout_track_offset = 0;
+       int in_track_num = -1, in_index_num = -1;
+       FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false;
+       FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
+
+       cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0;
+       cs->is_cd = is_cdda;
+
+       while(0 != fgets(buffer, sizeof(buffer), file)) {
+               (*last_line_read)++;
+               line = buffer;
+
+               {
+                       size_t linelen = strlen(line);
+                       if((linelen == sizeof(buffer)-1) && line[linelen-1] != '\n') {
+                               *error_message = "line too long";
+                               return false;
+                       }
+               }
+
+               if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                       if(0 == FLAC__STRCASECMP(field, "CATALOG")) {
+                               if(disc_has_catalog) {
+                                       *error_message = "found multiple CATALOG commands";
+                                       return false;
+                               }
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) {
+                                       *error_message = "CATALOG is missing catalog number";
+                                       return false;
+                               }
+                               if(strlen(field) >= sizeof(cs->media_catalog_number)) {
+                                       *error_message = "CATALOG number is too long";
+                                       return false;
+                               }
+                               if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) {
+                                       *error_message = "CD-DA CATALOG number must be 13 decimal digits";
+                                       return false;
+                               }
+                               strcpy(cs->media_catalog_number, field);
+                               disc_has_catalog = true;
+                       }
+                       else if(0 == FLAC__STRCASECMP(field, "FLAGS")) {
+                               if(track_has_flags) {
+                                       *error_message = "found multiple FLAGS commands";
+                                       return false;
+                               }
+                               if(in_track_num < 0 || in_index_num >= 0) {
+                                       *error_message = "FLAGS command must come after TRACK but before INDEX";
+                                       return false;
+                               }
+                               while(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       if(0 == FLAC__STRCASECMP(field, "PRE"))
+                                               cs->tracks[cs->num_tracks-1].pre_emphasis = 1;
+                               }
+                               track_has_flags = true;
+                       }
+                       else if(0 == FLAC__STRCASECMP(field, "INDEX")) {
+                               FLAC__int64 xx;
+                               FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1];
+                               if(in_track_num < 0) {
+                                       *error_message = "found INDEX before any TRACK";
+                                       return false;
+                               }
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       *error_message = "INDEX is missing index number";
+                                       return false;
+                               }
+                               in_index_num = local__parse_int_(field);
+                               if(in_index_num < 0) {
+                                       *error_message = "INDEX has invalid index number";
+                                       return false;
+                               }
+                               FLAC__ASSERT(cs->num_tracks > 0);
+                               if(track->num_indices == 0) {
+                                       /* it's the first index point of the track */
+                                       if(in_index_num > 1) {
+                                               *error_message = "first INDEX number of a TRACK must be 0 or 1";
+                                               return false;
+                                       }
+                               }
+                               else {
+                                       if(in_index_num != track->indices[track->num_indices-1].number + 1) {
+                                               *error_message = "INDEX numbers must be sequential";
+                                               return false;
+                                       }
+                               }
+                               if(is_cdda && in_index_num > 99) {
+                                       *error_message = "CD-DA INDEX number must be between 0 and 99, inclusive";
+                                       return false;
+                               }
+                               /*@@@ search for duplicate track number? */
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       *error_message = "INDEX is missing an offset after the index number";
+                                       return false;
+                               }
+                               xx = local__parse_msf_(field);
+                               if(xx < 0) {
+                                       if(is_cdda) {
+                                               *error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
+                                               return false;
+                                       }
+                                       xx = local__parse_int64_(field);
+                                       if(xx < 0) {
+                                               *error_message = "illegal INDEX offset";
+                                               return false;
+                                       }
+                               }
+                               if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) {
+                                       *error_message = "first INDEX of first TRACK must have an offset of 00:00:00";
+                                       return false;
+                               }
+                               if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) {
+                                       *error_message = "CD-DA INDEX offsets must increase in time";
+                                       return false;
+                               }
+                               /* fill in track offset if it's the first index of the track */
+                               if(track->num_indices == 0)
+                                       track->offset = (FLAC__uint64)xx;
+                               if(is_cdda && cs->num_tracks > 1) {
+                                       const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2];
+                                       if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) {
+                                               *error_message = "CD-DA INDEX offsets must increase in time";
+                                               return false;
+                                       }
+                               }
+                               if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) {
+                                       *error_message = "memory allocation error";
+                                       return false;
+                               }
+                               track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset;
+                               track->indices[track->num_indices-1].number = in_index_num;
+                       }
+                       else if(0 == FLAC__STRCASECMP(field, "ISRC")) {
+                               char *l, *r;
+                               if(track_has_isrc) {
+                                       *error_message = "found multiple ISRC commands";
+                                       return false;
+                               }
+                               if(in_track_num < 0 || in_index_num >= 0) {
+                                       *error_message = "ISRC command must come after TRACK but before INDEX";
+                                       return false;
+                               }
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       *error_message = "ISRC is missing ISRC number";
+                                       return false;
+                               }
+                               /* strip out dashes */
+                               for(l = r = field; *r; r++) {
+                                       if(*r != '-')
+                                               *l++ = *r;
+                               }
+                               *l = '\0';
+                               if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) {
+                                       *error_message = "invalid ISRC number";
+                                       return false;
+                               }
+                               strcpy(cs->tracks[cs->num_tracks-1].isrc, field);
+                               track_has_isrc = true;
+                       }
+                       else if(0 == FLAC__STRCASECMP(field, "TRACK")) {
+                               if(cs->num_tracks > 0) {
+                                       const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+                                       if(
+                                               prev->num_indices == 0 ||
+                                               (
+                                                       is_cdda &&
+                                                       (
+                                                               (prev->num_indices == 1 && prev->indices[0].number != 1) ||
+                                                               (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+                                                       )
+                                               )
+                                       ) {
+                                               *error_message = is_cdda?
+                                                       "previous TRACK must specify at least one INDEX 01" :
+                                                       "previous TRACK must specify at least one INDEX";
+                                               return false;
+                                       }
+                               }
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       *error_message = "TRACK is missing track number";
+                                       return false;
+                               }
+                               in_track_num = local__parse_int_(field);
+                               if(in_track_num < 0) {
+                                       *error_message = "TRACK has invalid track number";
+                                       return false;
+                               }
+                               if(in_track_num == 0) {
+                                       *error_message = "TRACK number must be greater than 0";
+                                       return false;
+                               }
+                               if(is_cdda) {
+                                       if(in_track_num > 99) {
+                                               *error_message = "CD-DA TRACK number must be between 1 and 99, inclusive";
+                                               return false;
+                                       }
+                               }
+                               else {
+                                       if(in_track_num == 255) {
+                                               *error_message = "TRACK number 255 is reserved for the lead-out";
+                                               return false;
+                                       }
+                                       else if(in_track_num > 255) {
+                                               *error_message = "TRACK number must be between 1 and 254, inclusive";
+                                               return false;
+                                       }
+                               }
+                               if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) {
+                                       *error_message = "CD-DA TRACK numbers must be sequential";
+                                       return false;
+                               }
+                               /*@@@ search for duplicate track number? */
+                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       *error_message = "TRACK is missing a track type after the track number";
+                                       return false;
+                               }
+                               if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+                                       *error_message = "memory allocation error";
+                                       return false;
+                               }
+                               cs->tracks[cs->num_tracks-1].number = in_track_num;
+                               cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */
+                               in_index_num = -1;
+                               track_has_flags = false;
+                               track_has_isrc = false;
+                       }
+                       else if(0 == FLAC__STRCASECMP(field, "REM")) {
+                               if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                       if(0 == strcmp(field, "FLAC__lead-in")) {
+                                               FLAC__int64 xx;
+                                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                                       *error_message = "FLAC__lead-in is missing offset";
+                                                       return false;
+                                               }
+                                               xx = local__parse_int64_(field);
+                                               if(xx < 0) {
+                                                       *error_message = "illegal FLAC__lead-in offset";
+                                                       return false;
+                                               }
+                                               if(is_cdda && xx % 588 != 0) {
+                                                       *error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples";
+                                                       return false;
+                                               }
+                                               cs->lead_in = (FLAC__uint64)xx;
+                                       }
+                                       else if(0 == strcmp(field, "FLAC__lead-out")) {
+                                               int track_num;
+                                               FLAC__int64 offset;
+                                               if(has_forced_leadout) {
+                                                       *error_message = "multiple FLAC__lead-out commands";
+                                                       return false;
+                                               }
+                                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                                       *error_message = "FLAC__lead-out is missing track number";
+                                                       return false;
+                                               }
+                                               track_num = local__parse_int_(field);
+                                               if(track_num < 0) {
+                                                       *error_message = "illegal FLAC__lead-out track number";
+                                                       return false;
+                                               }
+                                               forced_leadout_track_num = (unsigned)track_num;
+                                               /*@@@ search for duplicate track number? */
+                                               if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+                                                       *error_message = "FLAC__lead-out is missing offset";
+                                                       return false;
+                                               }
+                                               offset = local__parse_int64_(field);
+                                               if(offset < 0) {
+                                                       *error_message = "illegal FLAC__lead-out offset";
+                                                       return false;
+                                               }
+                                               forced_leadout_track_offset = (FLAC__uint64)offset;
+                                               if(forced_leadout_track_offset != lead_out_offset) {
+                                                       *error_message = "FLAC__lead-out offset does not match end-of-stream offset";
+                                                       return false;
+                                               }
+                                               has_forced_leadout = true;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(cs->num_tracks == 0) {
+               *error_message = "there must be at least one TRACK command";
+               return false;
+       }
+       else {
+               const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+               if(
+                       prev->num_indices == 0 ||
+                       (
+                               is_cdda &&
+                               (
+                                       (prev->num_indices == 1 && prev->indices[0].number != 1) ||
+                                       (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+                               )
+                       )
+               ) {
+                       *error_message = is_cdda?
+                               "previous TRACK must specify at least one INDEX 01" :
+                               "previous TRACK must specify at least one INDEX";
+                       return false;
+               }
+       }
+
+       if(!has_forced_leadout) {
+               forced_leadout_track_num = is_cdda? 170 : 255;
+               forced_leadout_track_offset = lead_out_offset;
+       }
+       if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+               *error_message = "memory allocation error";
+               return false;
+       }
+       cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num;
+       cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset;
+
+       if(!feof(file)) {
+               *error_message = "read error";
+               return false;
+       }
+       return true;
+#undef FLAC__STRCASECMP
+}
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+       FLAC__StreamMetadata *cuesheet;
+
+       FLAC__ASSERT(0 != file);
+       FLAC__ASSERT(0 != error_message);
+       FLAC__ASSERT(0 != last_line_read);
+
+       *last_line_read = 0;
+       cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+
+       if(0 == cuesheet) {
+               *error_message = "memory allocation error";
+               return 0;
+       }
+
+       if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, is_cdda, lead_out_offset)) {
+               FLAC__metadata_object_delete(cuesheet);
+               return 0;
+       }
+
+       return cuesheet;
+}
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference)
+{
+       const FLAC__StreamMetadata_CueSheet *cs;
+       unsigned track_num, index_num;
+
+       FLAC__ASSERT(0 != file);
+       FLAC__ASSERT(0 != cuesheet);
+       FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       cs = &cuesheet->data.cue_sheet;
+
+       if(*(cs->media_catalog_number))
+               fprintf(file, "CATALOG %s\n", cs->media_catalog_number);
+       fprintf(file, "FILE %s\n", file_reference);
+
+       for(track_num = 0; track_num < cs->num_tracks-1; track_num++) {
+               const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num;
+
+               fprintf(file, "  TRACK %02u %s\n", (unsigned)track->number, track->type == 0? "AUDIO" : "DATA");
+
+               if(track->pre_emphasis)
+                       fprintf(file, "    FLAGS PRE\n");
+               if(*(track->isrc))
+                       fprintf(file, "    ISRC %s\n", track->isrc);
+
+               for(index_num = 0; index_num < track->num_indices; index_num++) {
+                       const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + index_num;
+
+                       fprintf(file, "    INDEX %02u ", (unsigned)index->number);
+                       if(cs->is_cd) {
+                               const unsigned logical_frame = (unsigned)((track->offset + index->offset) / (44100 / 75));
+                               unsigned m, s, f;
+                               grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
+                               fprintf(file, "%02u:%02u:%02u\n", m, s, f);
+                       }
+                       else
+#ifdef _MSC_VER
+                               fprintf(file, "%I64u\n", track->offset + index->offset);
+#else
+                               fprintf(file, "%llu\n", (unsigned long long)(track->offset + index->offset));
+#endif
+               }
+       }
+
+#ifdef _MSC_VER
+       fprintf(file, "REM FLAC__lead-in %I64u\n", cs->lead_in);
+       fprintf(file, "REM FLAC__lead-out %u %I64u\n", (unsigned)cs->tracks[track_num].number, cs->tracks[track_num].offset);
+#else
+       fprintf(file, "REM FLAC__lead-in %llu\n", (unsigned long long)cs->lead_in);
+       fprintf(file, "REM FLAC__lead-out %u %llu\n", (unsigned)cs->tracks[track_num].number, (unsigned long long)cs->tracks[track_num].offset);
+#endif
+}
diff --git a/src/share/grabbag/file.c b/src/share/grabbag/file.c
new file mode 100644 (file)
index 0000000..d073c4b
--- /dev/null
@@ -0,0 +1,192 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod(), _setmode(), unlink() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#if defined _WIN32 && !defined __CYGWIN__
+#else
+#include <unistd.h> /* for unlink() */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strrchr() */
+#if defined _WIN32 && !defined __CYGWIN__
+// for GetFileInformationByHandle() etc
+#include <windows.h>
+#include <winbase.h>
+#endif
+#include "share/grabbag.h"
+
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
+{
+       struct stat srcstat;
+       struct utimbuf srctime;
+
+       if(0 == stat(srcpath, &srcstat)) {
+               srctime.actime = srcstat.st_atime;
+               srctime.modtime = srcstat.st_mtime;
+               (void)chmod(destpath, srcstat.st_mode);
+               (void)utime(destpath, &srctime);
+       }
+}
+
+off_t grabbag__file_get_filesize(const char *srcpath)
+{
+       struct stat srcstat;
+
+       if(0 == stat(srcpath, &srcstat))
+               return srcstat.st_size;
+       else
+               return -1;
+}
+
+const char *grabbag__file_get_basename(const char *srcpath)
+{
+       const char *p;
+
+       p = strrchr(srcpath, '/');
+       if(0 == p) {
+               p = strrchr(srcpath, '\\');
+               if(0 == p)
+                       return srcpath;
+       }
+       return ++p;
+}
+
+FLAC__bool grabbag__file_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;
+               }
+#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 grabbag__file_are_same(const char *f1, const char *f2)
+{
+#if defined _MSC_VER || defined __MINGW32__
+       /* see
+        * http://www.hydrogenaudio.org/forums/index.php?showtopic=49439&pid=444300&st=0
+        *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileinformationbyhandle.asp
+        *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/by_handle_file_information_str.asp
+        *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp
+        * apparently both the files have to be open at the same time for the comparison to work
+        */
+       FLAC__bool same = false;
+       BY_HANDLE_FILE_INFORMATION info1, info2;
+       HANDLE h1, h2;
+       BOOL ok = 1;
+       h1 = CreateFile(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+       h2 = CreateFile(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+       if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
+               ok = 0;
+       ok &= GetFileInformationByHandle(h1, &info1);
+       ok &= GetFileInformationByHandle(h2, &info2);
+       if(ok)
+               same =
+                       info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+                       info1.nFileIndexHigh == info2.nFileIndexHigh &&
+                       info1.nFileIndexLow == info2.nFileIndexLow
+               ;
+       if(h1 != INVALID_HANDLE_VALUE)
+               CloseHandle(h1);
+       if(h2 != INVALID_HANDLE_VALUE)
+               CloseHandle(h2);
+       return same;
+#else
+       struct stat s1, s2;
+       return f1 && f2 && stat(f1, &s1) == 0 && stat(f2, &s2) == 0 && s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
+#endif
+}
+
+FLAC__bool grabbag__file_remove_file(const char *filename)
+{
+       return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename);
+}
+
+FILE *grabbag__file_get_binary_stdin(void)
+{
+       /* if something breaks here it is probably due to the presence or
+        * absence of an underscore before the identifiers 'setmode',
+        * 'fileno', and/or 'O_BINARY'; check your system header files.
+        */
+#if defined _MSC_VER || defined __MINGW32__
+       _setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__
+       /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+       setmode(_fileno(stdin), _O_BINARY);
+#elif defined __EMX__
+       setmode(fileno(stdin), O_BINARY);
+#endif
+
+       return stdin;
+}
+
+FILE *grabbag__file_get_binary_stdout(void)
+{
+       /* if something breaks here it is probably due to the presence or
+        * absence of an underscore before the identifiers 'setmode',
+        * 'fileno', and/or 'O_BINARY'; check your system header files.
+        */
+#if defined _MSC_VER || defined __MINGW32__
+       _setmode(_fileno(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+       /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+       setmode(_fileno(stdout), _O_BINARY);
+#elif defined __EMX__
+       setmode(fileno(stdout), O_BINARY);
+#endif
+
+       return stdout;
+}
diff --git a/src/share/grabbag/grabbag_static.dsp b/src/share/grabbag/grabbag_static.dsp
new file mode 100644 (file)
index 0000000..750b153
--- /dev/null
@@ -0,0 +1,144 @@
+# Microsoft Developer Studio Project File - Name="grabbag_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=grabbag_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "grabbag_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "grabbag_static.mak" CFG="grabbag_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "grabbag_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "grabbag_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "grabbag"\r
+# PROP Scc_LocalPath "..\..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "grabbag_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /Op /I ".\include" /I "..\..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "grabbag_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "grabbag_static - Win32 Release"\r
+# Name "grabbag_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\cuesheet.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\file.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\picture.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\replaygain.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\seektable.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag\cuesheet.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag\file.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag\picture.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag\replaygain.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag\seektable.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\grabbag.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/share/grabbag/grabbag_static.vcproj b/src/share/grabbag/grabbag_static.vcproj
new file mode 100644 (file)
index 0000000..61d230d
--- /dev/null
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="grabbag_static"\r
+       ProjectGUID="{4cefbc81-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="grabbag_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\cuesheet.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\file.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\picture.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\replaygain.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\seektable.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\include\share\grabbag.h"\r
+                               >\r
+                       </File>\r
+                       <Filter\r
+                               Name="grabbag"\r
+                               >\r
+                               <File\r
+                                       RelativePath="..\..\..\include\share\grabbag\cuesheet.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\include\share\grabbag\file.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\include\share\grabbag\picture.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\include\share\grabbag\replaygain.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\include\share\grabbag\seektable.h"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/share/grabbag/picture.c b/src/share/grabbag/picture.c
new file mode 100644 (file)
index 0000000..0e37273
--- /dev/null
@@ -0,0 +1,407 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* slightly different that strndup(): this always copies 'size' bytes starting from s into a NUL-terminated string. */
+static char *local__strndup_(const char *s, size_t size)
+{
+       char *x = (char*)safe_malloc_add_2op_(size, /*+*/1);
+       if(x) {
+               memcpy(x, s, size);
+               x[size] = '\0';
+       }
+       return x;
+}
+
+static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+       size_t i;
+       FLAC__uint32 val = 0;
+
+       picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+
+       if(len == 0)
+               return true; /* empty string implies default to 'front cover' */
+
+       for(i = 0; i < len; i++) {
+               if(s[i] >= '0' && s[i] <= '9')
+                       val = 10*val + (FLAC__uint32)(s[i] - '0');
+               else
+                       return false;
+       }
+
+       if(i == len)
+               picture->type = val;
+       else
+               return false;
+
+       return true;
+}
+
+static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+       int state = 0;
+       size_t i;
+       FLAC__uint32 val = 0;
+
+       picture->width = picture->height = picture->depth = picture->colors = 0;
+
+       if(len == 0)
+               return true; /* empty string implies client wants to get info from the file itself */
+
+       for(i = 0; i < len; i++) {
+               if(s[i] == 'x') {
+                       if(state == 0)
+                               picture->width = val;
+                       else if(state == 1)
+                               picture->height = val;
+                       else
+                               return false;
+                       state++;
+                       val = 0;
+               }
+               else if(s[i] == '/') {
+                       if(state == 2)
+                               picture->depth = val;
+                       else
+                               return false;
+                       state++;
+                       val = 0;
+               }
+               else if(s[i] >= '0' && s[i] <= '9')
+                       val = 10*val + (FLAC__uint32)(s[i] - '0');
+               else
+                       return false;
+       }
+
+       if(state < 2)
+               return false;
+       else if(state == 2)
+               picture->depth = val;
+       else if(state == 3)
+               picture->colors = val;
+       else
+               return false;
+       if(picture->depth < 32 && 1u<<picture->depth < picture->colors)
+               return false;
+
+       return true;
+}
+
+static FLAC__bool local__extract_mime_type_(FLAC__StreamMetadata *obj)
+{
+       if(obj->data.picture.data_length >= 8 && 0 == memcmp(obj->data.picture.data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+               return FLAC__metadata_object_picture_set_mime_type(obj, "image/png", /*copy=*/true);
+       else if(obj->data.picture.data_length >= 6 && (0 == memcmp(obj->data.picture.data, "GIF87a", 6) || 0 == memcmp(obj->data.picture.data, "GIF89a", 6)))
+               return FLAC__metadata_object_picture_set_mime_type(obj, "image/gif", /*copy=*/true);
+       else if(obj->data.picture.data_length >= 2 && 0 == memcmp(obj->data.picture.data, "\xff\xd8", 2))
+               return FLAC__metadata_object_picture_set_mime_type(obj, "image/jpeg", /*copy=*/true);
+       return false;
+}
+
+static FLAC__bool local__extract_resolution_color_info_(FLAC__StreamMetadata_Picture *picture)
+{
+       const FLAC__byte *data = picture->data;
+       FLAC__uint32 len = picture->data_length;
+
+       if(0 == strcmp(picture->mime_type, "image/png")) {
+               /* c.f. http://www.w3.org/TR/PNG/ */
+               FLAC__bool need_palette = false; /* if IHDR has color_type=3, we need to also read the PLTE chunk to get the #colors */
+               if(len < 8 || memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+                       return false;
+               /* try to find IHDR chunk */
+               data += 8;
+               len -= 8;
+               while(len > 12) { /* every PNG chunk must be at least 12 bytes long */
+                       const FLAC__uint32 clen = (FLAC__uint32)data[0] << 24 | (FLAC__uint32)data[1] << 16 | (FLAC__uint32)data[2] << 8 | (FLAC__uint32)data[3];
+                       if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) {
+                               unsigned color_type = data[17];
+                               picture->width = (FLAC__uint32)data[8] << 24 | (FLAC__uint32)data[9] << 16 | (FLAC__uint32)data[10] << 8 | (FLAC__uint32)data[11];
+                               picture->height = (FLAC__uint32)data[12] << 24 | (FLAC__uint32)data[13] << 16 | (FLAC__uint32)data[14] << 8 | (FLAC__uint32)data[15];
+                               if(color_type == 3) {
+                                       /* even though the bit depth for color_type==3 can be 1,2,4,or 8,
+                                        * the spec in 11.2.2 of http://www.w3.org/TR/PNG/ says that the
+                                        * sample depth is always 8
+                                        */
+                                       picture->depth = 8 * 3u;
+                                       need_palette = true;
+                                       data += 12 + clen;
+                                       len -= 12 + clen;
+                               }
+                               else {
+                                       if(color_type == 0) /* greyscale, 1 sample per pixel */
+                                               picture->depth = (FLAC__uint32)data[16];
+                                       if(color_type == 2) /* truecolor, 3 samples per pixel */
+                                               picture->depth = (FLAC__uint32)data[16] * 3u;
+                                       if(color_type == 4) /* greyscale+alpha, 2 samples per pixel */
+                                               picture->depth = (FLAC__uint32)data[16] * 2u;
+                                       if(color_type == 6) /* truecolor+alpha, 4 samples per pixel */
+                                               picture->depth = (FLAC__uint32)data[16] * 4u;
+                                       picture->colors = 0;
+                                       return true;
+                               }
+                       }
+                       else if(need_palette && 0 == memcmp(data+4, "PLTE", 4)) {
+                               picture->colors = clen / 3u;
+                               return true;
+                       }
+                       else if(clen + 12 > len)
+                               return false;
+                       else {
+                               data += 12 + clen;
+                               len -= 12 + clen;
+                       }
+               }
+       }
+       else if(0 == strcmp(picture->mime_type, "image/jpeg")) {
+               /* c.f. http://www.w3.org/Graphics/JPEG/itu-t81.pdf and Q22 of http://www.faqs.org/faqs/jpeg-faq/part1/ */
+               if(len < 2 || memcmp(data, "\xff\xd8", 2))
+                       return false;
+               data += 2;
+               len -= 2;
+               while(1) {
+                       /* look for sync FF byte */
+                       for( ; len > 0; data++, len--) {
+                               if(*data == 0xff)
+                                       break;
+                       }
+                       if(len == 0)
+                               return false;
+                       /* eat any extra pad FF bytes before marker */
+                       for( ; len > 0; data++, len--) {
+                               if(*data != 0xff)
+                                       break;
+                       }
+                       if(len == 0)
+                               return false;
+                       /* if we hit SOS or EOI, bail */
+                       if(*data == 0xda || *data == 0xd9)
+                               return false;
+                       /* looking for some SOFn */
+                       else if(memchr("\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf", *data, 13)) {
+                               data++; len--; /* skip marker byte */
+                               if(len < 2)
+                                       return false;
+                               else {
+                                       const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+                                       if(clen < 8 || len < clen)
+                                               return false;
+                                       picture->width = (FLAC__uint32)data[5] << 8 | (FLAC__uint32)data[6];
+                                       picture->height = (FLAC__uint32)data[3] << 8 | (FLAC__uint32)data[4];
+                                       picture->depth = (FLAC__uint32)data[2] * (FLAC__uint32)data[7];
+                                       picture->colors = 0;
+                                       return true;
+                               }
+                       }
+                       /* else skip it */
+                       else {
+                               data++; len--; /* skip marker byte */
+                               if(len < 2)
+                                       return false;
+                               else {
+                                       const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+                                       if(clen < 2 || len < clen)
+                                               return false;
+                                       data += clen;
+                                       len -= clen;
+                               }
+                       }
+               }
+       }
+       else if(0 == strcmp(picture->mime_type, "image/gif")) {
+               /* c.f. http://www.w3.org/Graphics/GIF/spec-gif89a.txt */
+               if(len < 14)
+                       return false;
+               if(memcmp(data, "GIF87a", 6) && memcmp(data, "GIF89a", 6))
+                       return false;
+#if 0
+               /* according to the GIF spec, even if the GCTF is 0, the low 3 bits should still tell the total # colors used */
+               if(data[10] & 0x80 == 0)
+                       return false;
+#endif
+               picture->width = (FLAC__uint32)data[6] | ((FLAC__uint32)data[7] << 8);
+               picture->height = (FLAC__uint32)data[8] | ((FLAC__uint32)data[9] << 8);
+#if 0
+               /* this value doesn't seem to be reliable... */
+               picture->depth = (((FLAC__uint32)(data[10] & 0x70) >> 4) + 1) * 3u;
+#else
+               /* ...just pessimistically assume it's 24-bit color without scanning all the color tables */
+               picture->depth = 8u * 3u;
+#endif
+               picture->colors = 1u << ((FLAC__uint32)(data[10] & 0x07) + 1u);
+               return true;
+       }
+       return false;
+}
+
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message)
+{
+       FLAC__StreamMetadata *obj;
+       int state = 0;
+       static const char *error_messages[] = {
+               "memory allocation error",
+               "invalid picture specification",
+               "invalid picture specification: can't parse resolution/color part",
+               "unable to extract resolution and color info from URL, user must set explicitly",
+               "unable to extract resolution and color info from file, user must set explicitly",
+               "error opening picture file",
+               "error reading picture file",
+               "invalid picture type",
+               "unable to guess MIME type from file, user must set explicitly",
+               "type 1 icon must be a 32x32 pixel PNG"
+       };
+
+       FLAC__ASSERT(0 != spec);
+       FLAC__ASSERT(0 != error_message);
+
+       /* double protection */
+       if(0 == spec)
+               return 0;
+       if(0 == error_message)
+               return 0;
+
+       *error_message = 0;
+
+       if(0 == (obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)))
+               *error_message = error_messages[0];
+
+       if(strchr(spec, '|')) { /* full format */
+               const char *p;
+               char *q;
+               for(p = spec; *error_message==0 && *p; ) {
+                       if(*p == '|') {
+                               switch(state) {
+                                       case 0: /* type */
+                                               if(!local__parse_type_(spec, p-spec, &obj->data.picture))
+                                                       *error_message = error_messages[7];
+                                               break;
+                                       case 1: /* mime type */
+                                               if(p-spec) { /* if blank, we'll try to guess later from the picture data */
+                                                       if(0 == (q = local__strndup_(spec, p-spec)))
+                                                               *error_message = error_messages[0];
+                                                       else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false))
+                                                               *error_message = error_messages[0];
+                                               }
+                                               break;
+                                       case 2: /* description */
+                                               if(0 == (q = local__strndup_(spec, p-spec)))
+                                                       *error_message = error_messages[0];
+                                               else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false))
+                                                       *error_message = error_messages[0];
+                                               break;
+                                       case 3: /* resolution/color (e.g. [300x300x16[/1234]] */
+                                               if(!local__parse_resolution_(spec, p-spec, &obj->data.picture))
+                                                       *error_message = error_messages[2];
+                                               break;
+                                       default:
+                                               *error_message = error_messages[1];
+                                               break;
+                               }
+                               p++;
+                               spec = p;
+                               state++;
+                       }
+                       else
+                               p++;
+               }
+       }
+       else { /* simple format, filename only, everything else guessed */
+               if(!local__parse_type_("", 0, &obj->data.picture)) /* use default picture type */
+                       *error_message = error_messages[7];
+               /* leave MIME type to be filled in later */
+               /* leave description empty */
+               /* leave the rest to be filled in later: */
+               else if(!local__parse_resolution_("", 0, &obj->data.picture))
+                       *error_message = error_messages[2];
+               else
+                       state = 4;
+       }
+
+       /* parse filename, read file, try to extract resolution/color info if needed */
+       if(*error_message == 0) {
+               if(state != 4)
+                       *error_message = error_messages[1];
+               else { /* 'spec' points to filename/URL */
+                       if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */
+                               if(!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)spec, strlen(spec), /*copy=*/true))
+                                       *error_message = error_messages[0];
+                               else if(obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0)
+                                       *error_message = error_messages[3];
+                       }
+                       else { /* regular picture file */
+                               const off_t size = grabbag__file_get_filesize(spec);
+                               if(size < 0)
+                                       *error_message = error_messages[5];
+                               else {
+                                       FLAC__byte *buffer = (FLAC__byte*)safe_malloc_(size);
+                                       if(0 == buffer)
+                                               *error_message = error_messages[0];
+                                       else {
+                                               FILE *f = fopen(spec, "rb");
+                                               if(0 == f)
+                                                       *error_message = error_messages[5];
+                                               else {
+                                                       if(fread(buffer, 1, size, f) != (size_t)size)
+                                                               *error_message = error_messages[6];
+                                                       fclose(f);
+                                                       if(0 == *error_message) {
+                                                               if(!FLAC__metadata_object_picture_set_data(obj, buffer, size, /*copy=*/false))
+                                                                       *error_message = error_messages[6];
+                                                               /* try to extract MIME type if user left it blank */
+                                                               else if(*obj->data.picture.mime_type == '\0' && !local__extract_mime_type_(obj))
+                                                                       *error_message = error_messages[8];
+                                                               /* try to extract resolution/color info if user left it blank */
+                                                               else if((obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) && !local__extract_resolution_color_info_(&obj->data.picture))
+                                                                       *error_message = error_messages[4];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(*error_message == 0) {
+               if(
+                       obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && 
+                       (
+                               (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) ||
+                               obj->data.picture.width != 32 ||
+                               obj->data.picture.height != 32
+                       )
+               )
+                       *error_message = error_messages[9];
+       }
+
+       if(*error_message && obj) {
+               FLAC__metadata_object_delete(obj);
+               obj = 0;
+       }
+
+       return obj;
+}
diff --git a/src/share/grabbag/replaygain.c b/src/share/grabbag/replaygain.c
new file mode 100644 (file)
index 0000000..b3d3d21
--- /dev/null
@@ -0,0 +1,668 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "share/replaygain_analysis.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for chmod() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#ifdef local_min
+#undef local_min
+#endif
+#define local_min(a,b) ((a)<(b)?(a):(b))
+
+#ifdef local_max
+#undef local_max
+#endif
+#define local_max(a,b) ((a)>(b)?(a):(b))
+
+static const char *reference_format_ = "%s=%2.1f dB";
+static const char *gain_format_ = "%s=%+2.2f dB";
+static const char *peak_format_ = "%s=%1.8f";
+
+static double album_peak_, title_peak_;
+
+const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
+/*
+       FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
+       FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+       FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
+       FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+       FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
+*/
+
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
+
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+       return (0 == stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct stat *stats)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+
+       (void)chmod(filename, stats->st_mode);
+}
+
+static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value)
+{
+       char buffer[256];
+       char *saved_locale;
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       FLAC__ASSERT(0 != format);
+       FLAC__ASSERT(0 != name);
+
+       buffer[sizeof(buffer)-1] = '\0';
+       /*
+        * We need to save the old locale and switch to "C" because the locale
+        * influences the formatting of %f and we want it a certain way.
+        */
+       saved_locale = strdup(setlocale(LC_ALL, 0));
+       if (0 == saved_locale)
+               return false;
+       setlocale(LC_ALL, "C");
+#if defined _MSC_VER || defined __MINGW32__
+       _snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#else
+       snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#endif
+       setlocale(LC_ALL, saved_locale);
+       free(saved_locale);
+
+       entry.entry = (FLAC__byte *)buffer;
+       entry.length = strlen(buffer);
+
+       return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
+}
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency)
+{
+       static const unsigned valid_sample_rates[] = {
+               8000,
+               11025,
+               12000,
+               16000,
+               22050,
+               24000,
+               32000,
+               44100,
+               48000
+       };
+       static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]);
+
+       unsigned i;
+
+       for(i = 0; i < n_valid_sample_rates; i++)
+               if(sample_frequency == valid_sample_rates[i])
+                       return true;
+       return false;
+}
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency)
+{
+       title_peak_ = album_peak_ = 0.0;
+       return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK;
+}
+
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples)
+{
+       /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
+       static Float_t lbuffer[2048], rbuffer[2048];
+       static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
+       FLAC__int32 block_peak = 0, s;
+       unsigned i, j;
+
+       FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE);
+       FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4);
+       /*
+        * We use abs() on a FLAC__int32 which is undefined for the most negative value.
+        * If the reference codec ever handles 32bps we will have to write a special
+        * case here.
+        */
+       FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32);
+
+       if(bps == 16) {
+               if(is_stereo) {
+                       j = 0;
+                       while(samples > 0) {
+                               const unsigned n = local_min(samples, nbuffer);
+                               for(i = 0; i < n; i++, j++) {
+                                       s = input[0][j];
+                                       lbuffer[i] = (Float_t)s;
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+
+                                       s = input[1][j];
+                                       rbuffer[i] = (Float_t)s;
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+                               }
+                               samples -= n;
+                               if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+                                       return false;
+                       }
+               }
+               else {
+                       j = 0;
+                       while(samples > 0) {
+                               const unsigned n = local_min(samples, nbuffer);
+                               for(i = 0; i < n; i++, j++) {
+                                       s = input[0][j];
+                                       lbuffer[i] = (Float_t)s;
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+                               }
+                               samples -= n;
+                               if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+                                       return false;
+                       }
+               }
+       }
+       else { /* bps must be < 32 according to above assertion */
+               const double scale = (
+                       (bps > 16)?
+                               (double)1. / (double)(1u << (bps - 16)) :
+                               (double)(1u << (16 - bps))
+               );
+
+               if(is_stereo) {
+                       j = 0;
+                       while(samples > 0) {
+                               const unsigned n = local_min(samples, nbuffer);
+                               for(i = 0; i < n; i++, j++) {
+                                       s = input[0][j];
+                                       lbuffer[i] = (Float_t)(scale * (double)s);
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+
+                                       s = input[1][j];
+                                       rbuffer[i] = (Float_t)(scale * (double)s);
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+                               }
+                               samples -= n;
+                               if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+                                       return false;
+                       }
+               }
+               else {
+                       j = 0;
+                       while(samples > 0) {
+                               const unsigned n = local_min(samples, nbuffer);
+                               for(i = 0; i < n; i++, j++) {
+                                       s = input[0][j];
+                                       lbuffer[i] = (Float_t)(scale * (double)s);
+                                       s = abs(s);
+                                       block_peak = local_max(block_peak, s);
+                               }
+                               samples -= n;
+                               if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+                                       return false;
+                       }
+               }
+       }
+
+       {
+               const double peak_scale = (double)(1u << (bps - 1));
+               double peak = (double)block_peak / peak_scale;
+               if(peak > title_peak_)
+                       title_peak_ = peak;
+               if(peak > album_peak_)
+                       album_peak_ = peak;
+       }
+
+       return true;
+}
+
+void grabbag__replaygain_get_album(float *gain, float *peak)
+{
+       *gain = (float)GetAlbumGain();
+       *peak = (float)album_peak_;
+       album_peak_ = 0.0;
+}
+
+void grabbag__replaygain_get_title(float *gain, float *peak)
+{
+       *gain = (float)GetTitleGain();
+       *peak = (float)title_peak_;
+       title_peak_ = 0.0;
+}
+
+
+typedef struct {
+       unsigned channels;
+       unsigned bits_per_sample;
+       unsigned sample_rate;
+       FLAC__bool error;
+} DecoderInstance;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       DecoderInstance *instance = (DecoderInstance*)client_data;
+       const unsigned bits_per_sample = frame->header.bits_per_sample;
+       const unsigned channels = frame->header.channels;
+       const unsigned sample_rate = frame->header.sample_rate;
+       const unsigned samples = frame->header.blocksize;
+
+       (void)decoder;
+
+       if(
+               !instance->error &&
+               (channels == 2 || channels == 1) &&
+               bits_per_sample == instance->bits_per_sample &&
+               channels == instance->channels &&
+               sample_rate == instance->sample_rate
+       ) {
+               instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples);
+       }
+       else {
+               instance->error = true;
+       }
+
+       if(!instance->error)
+               return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+       else
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       DecoderInstance *instance = (DecoderInstance*)client_data;
+
+       (void)decoder;
+
+       if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               instance->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+               instance->channels = metadata->data.stream_info.channels;
+               instance->sample_rate = metadata->data.stream_info.sample_rate;
+
+               if(instance->channels != 1 && instance->channels != 2) {
+                       instance->error = true;
+                       return;
+               }
+
+               if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) {
+                       instance->error = true;
+                       return;
+               }
+       }
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       DecoderInstance *instance = (DecoderInstance*)client_data;
+
+       (void)decoder, (void)status;
+
+       instance->error = true;
+}
+
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
+{
+       DecoderInstance instance;
+       FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+
+       if(0 == decoder)
+               return "memory allocation error";
+
+       instance.error = false;
+
+       /* It does these three by default but lets be explicit: */
+       FLAC__stream_decoder_set_md5_checking(decoder, false);
+       FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+       FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+
+       if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               FLAC__stream_decoder_delete(decoder);
+               return "initializing decoder";
+       }
+
+       if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
+               FLAC__stream_decoder_delete(decoder);
+               return "decoding file";
+       }
+
+       FLAC__stream_decoder_delete(decoder);
+
+       grabbag__replaygain_get_title(title_gain, title_peak);
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak)
+{
+       const char *error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak)))
+               return error;
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
+{
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
+               return "memory allocation error";
+
+       if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
+               return "memory allocation error";
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
+{
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       if(
+               FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
+               FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
+       )
+               return "memory allocation error";
+
+       if(
+               !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
+               !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
+       )
+               return "memory allocation error";
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak)
+{
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       if(
+               FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
+               FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
+       )
+               return "memory allocation error";
+
+       if(
+               !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
+               !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
+       )
+               return "memory allocation error";
+
+       return 0;
+}
+
+static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block)
+{
+       FLAC__Metadata_Iterator *iterator;
+       const char *error;
+       FLAC__bool found_vc_block = false;
+
+       if(0 == (*chain = FLAC__metadata_chain_new()))
+               return "memory allocation error";
+
+       if(!FLAC__metadata_chain_read(*chain, filename)) {
+               error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+               FLAC__metadata_chain_delete(*chain);
+               return error;
+       }
+
+       if(0 == (iterator = FLAC__metadata_iterator_new())) {
+               FLAC__metadata_chain_delete(*chain);
+               return "memory allocation error";
+       }
+
+       FLAC__metadata_iterator_init(iterator, *chain);
+
+       do {
+               *block = FLAC__metadata_iterator_get_block(iterator);
+               if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+                       found_vc_block = true;
+       } while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+       if(!found_vc_block) {
+               /* create a new block */
+               *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+               if(0 == *block) {
+                       FLAC__metadata_chain_delete(*chain);
+                       FLAC__metadata_iterator_delete(iterator);
+                       return "memory allocation error";
+               }
+               while(FLAC__metadata_iterator_next(iterator))
+                       ;
+               if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) {
+                       error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+                       FLAC__metadata_chain_delete(*chain);
+                       FLAC__metadata_iterator_delete(iterator);
+                       return error;
+               }
+               /* iterator is left pointing to new block */
+               FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block);
+       }
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       FLAC__ASSERT(0 != *block);
+       FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       return 0;
+}
+
+static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime)
+{
+       struct stat stats;
+       const FLAC__bool have_stats = get_file_stats_(filename, &stats);
+
+       (void)grabbag__file_change_stats(filename, /*read_only=*/false);
+
+       FLAC__metadata_chain_sort_padding(chain);
+       if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) {
+               FLAC__metadata_chain_delete(chain);
+               return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
+       }
+
+       FLAC__metadata_chain_delete(chain);
+
+       if(have_stats)
+               set_file_stats_(filename, &stats);
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+       FLAC__Metadata_Chain *chain;
+       FLAC__StreamMetadata *block;
+       const char *error;
+
+       if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) {
+               FLAC__metadata_chain_delete(chain);
+               return error;
+       }
+
+       if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+               return error;
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
+{
+       FLAC__Metadata_Chain *chain;
+       FLAC__StreamMetadata *block;
+       const char *error;
+
+       if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
+               FLAC__metadata_chain_delete(chain);
+               return error;
+       }
+
+       if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+               return error;
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
+{
+       FLAC__Metadata_Chain *chain;
+       FLAC__StreamMetadata *block;
+       const char *error;
+
+       if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) {
+               FLAC__metadata_chain_delete(chain);
+               return error;
+       }
+
+       if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+               return error;
+
+       return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+       FLAC__Metadata_Chain *chain;
+       FLAC__StreamMetadata *block;
+       const char *error;
+
+       if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+               return error;
+
+       if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) {
+               FLAC__metadata_chain_delete(chain);
+               return error;
+       }
+
+       if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+               return error;
+
+       return 0;
+}
+
+static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val)
+{
+       char s[32], *end;
+       const char *p, *q;
+       double v;
+
+       FLAC__ASSERT(0 != entry);
+       FLAC__ASSERT(0 != val);
+
+       p = (const char *)entry->entry;
+       q = strchr(p, '=');
+       if(0 == q)
+               return false;
+       q++;
+       memset(s, 0, sizeof(s)-1);
+       strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p)));
+
+       v = strtod(s, &end);
+       if(end == s)
+               return false;
+
+       *val = v;
+       return true;
+}
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
+{
+       int reference_offset, gain_offset, peak_offset;
+
+       FLAC__ASSERT(0 != block);
+       FLAC__ASSERT(0 != reference);
+       FLAC__ASSERT(0 != gain);
+       FLAC__ASSERT(0 != peak);
+       FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       /* Default to current level until overridden by a detected tag; this
+        * will always be true until we change replaygain_analysis.c
+        */
+       *reference = ReplayGainReferenceLoudness;
+
+       if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
+               (void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
+
+       if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
+               return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+       if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
+               return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+       if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
+               return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+       if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
+               return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+       return true;
+}
+
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping)
+{
+       double scale;
+       FLAC__ASSERT(peak >= 0.0);
+       gain += preamp;
+       scale = (float) pow(10.0, gain * 0.05);
+       if(prevent_clipping && peak > 0.0) {
+               const double max_scale = (float)(1.0 / peak);
+               if(scale > max_scale)
+                       scale = max_scale;
+       }
+       return scale;
+}
diff --git a/src/share/grabbag/seektable.c b/src/share/grabbag/seektable.c
new file mode 100644 (file)
index 0000000..55ac766
--- /dev/null
@@ -0,0 +1,132 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdlib.h> /* for atoi() */
+#include <string.h>
+
+#ifdef _MSC_VER
+/* There's no strtoll() in MSVC6 so we just write a specialized one */
+static FLAC__int64 local__strtoll(const char *src, char **endptr)
+{
+       FLAC__bool neg = false;
+       FLAC__int64 ret = 0;
+       int c;
+       FLAC__ASSERT(0 != src);
+       if(*src == '-') {
+               neg = true;
+               src++;
+       }
+       while(0 != (c = *src)) {
+               c -= '0';
+               if(c >= 0 && c <= 9)
+                       ret = (ret * 10) + c;
+               else
+                       break;
+               src++;
+       }
+       if(endptr)
+               *endptr = (char*)src;
+       return neg? -ret : ret;
+}
+#endif
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points)
+{
+       unsigned i;
+       const char *pt;
+
+       FLAC__ASSERT(0 != spec);
+       FLAC__ASSERT(0 != seektable_template);
+       FLAC__ASSERT(seektable_template->type = FLAC__METADATA_TYPE_SEEKTABLE);
+
+       if(0 != spec_has_real_points)
+               *spec_has_real_points = false;
+
+       for(pt = spec, i = 0; pt && *pt; i++) {
+               const char *q = strchr(pt, ';');
+               FLAC__ASSERT(0 != q);
+
+               if(q > pt) {
+                       if(0 == strncmp(pt, "X;", 2)) { /* -S X */
+                               if(!FLAC__metadata_object_seektable_template_append_placeholders(seektable_template, 1))
+                                       return false;
+                       }
+                       else if(q[-1] == 'x') { /* -S #x */
+                               if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+                                       if(0 != spec_has_real_points)
+                                               *spec_has_real_points = true;
+                                       if(!only_explicit_placeholders) {
+                                               const int n = (unsigned)atoi(pt);
+                                               if(n > 0)
+                                                       if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (unsigned)n, total_samples_to_encode))
+                                                               return false;
+                                       }
+                               }
+                       }
+                       else if(q[-1] == 's') { /* -S #s */
+                               if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+                                       FLAC__ASSERT(sample_rate > 0);
+                                       if(0 != spec_has_real_points)
+                                               *spec_has_real_points = true;
+                                       if(!only_explicit_placeholders) {
+                                               const double sec = atof(pt);
+                                               if(sec > 0.0) {
+                                                       unsigned samples = (unsigned)(sec * (double)sample_rate);
+                                                       if(samples > 0) {
+                                                               /* +1 for the initial point at sample 0 */
+                                                               if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(seektable_template, samples, total_samples_to_encode))
+                                                                       return false;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else { /* -S # */
+                               if(0 != spec_has_real_points)
+                                       *spec_has_real_points = true;
+                               if(!only_explicit_placeholders) {
+                                       char *endptr;
+#ifdef _MSC_VER
+                                       const FLAC__int64 n = local__strtoll(pt, &endptr);
+#else
+                                       const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10);
+#endif
+                                       if(
+                                               (n > 0 || (endptr > pt && *endptr == ';')) && /* is a valid number (extra check needed for "0") */
+                                               (total_samples_to_encode == 0 || (FLAC__uint64)n < total_samples_to_encode) /* number is not >= the known total_samples_to_encode */
+                                       )
+                                               if(!FLAC__metadata_object_seektable_template_append_point(seektable_template, (FLAC__uint64)n))
+                                                       return false;
+                               }
+                       }
+               }
+
+               pt = ++q;
+       }
+
+       if(!FLAC__metadata_object_seektable_template_sort(seektable_template, /*compact=*/true))
+               return false;
+
+       return true;
+}
diff --git a/src/share/replaygain_analysis/Makefile.am b/src/share/replaygain_analysis/Makefile.am
new file mode 100644 (file)
index 0000000..de841aa
--- /dev/null
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/include/share
+
+noinst_LTLIBRARIES = libreplaygain_analysis.la
+
+libreplaygain_analysis_la_SOURCES = replaygain_analysis.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       replaygain_analysis_static.dsp \
+       replaygain_analysis_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/share/replaygain_analysis/Makefile.lite b/src/share/replaygain_analysis/Makefile.lite
new file mode 100644 (file)
index 0000000..8c4c698
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libreplaygain_analysis
+INCLUDES = -I$(topdir)/include/share
+
+SRCS_C = \
+       replaygain_analysis.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/replaygain_analysis/replaygain_analysis.c b/src/share/replaygain_analysis/replaygain_analysis.c
new file mode 100644 (file)
index 0000000..c64231f
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ *  Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  concept and filter values by David Robinson (David@Robinson.org)
+ *    -- blame him if you think the idea is flawed
+ *  original coding by Glen Sawyer (glensawyer@hotmail.com)
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *
+ *  lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
+ *    -- credit him for all the _good_ programming ;)
+ *
+ *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ *
+ *  For an explanation of the concepts and the basic algorithms involved, go to:
+ *    http://www.replaygain.org/
+ */
+
+/*
+ *  Here's the deal. Call
+ *
+ *    InitGainAnalysis ( long samplefreq );
+ *
+ *  to initialize everything. Call
+ *
+ *    AnalyzeSamples ( const Float_t*  left_samples,
+ *                     const Float_t*  right_samples,
+ *                     size_t          num_samples,
+ *                     int             num_channels );
+ *
+ *  as many times as you want, with as many or as few samples as you want.
+ *  If mono, pass the sample buffer in through left_samples, leave
+ *  right_samples NULL, and make sure num_channels = 1.
+ *
+ *    GetTitleGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
+ *
+ *    GetAlbumGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  since InitGainAnalysis() was called and finalized with GetTitleGain().
+ *
+ *  Pseudo-code to process an album:
+ *
+ *    Float_t       l_samples [4096];
+ *    Float_t       r_samples [4096];
+ *    size_t        num_samples;
+ *    unsigned int  num_songs;
+ *    unsigned int  i;
+ *
+ *    InitGainAnalysis ( 44100 );
+ *    for ( i = 1; i <= num_songs; i++ ) {
+ *        while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
+ *            AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
+ *        fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
+ *    }
+ *    fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
+ */
+
+/*
+ *  So here's the main source of potential code confusion:
+ *
+ *  The filters applied to the incoming samples are IIR filters,
+ *  meaning they rely on up to <filter order> number of previous samples
+ *  AND up to <filter order> number of previous filtered samples.
+ *
+ *  I set up the AnalyzeSamples routine to minimize memory usage and interface
+ *  complexity. The speed isn't compromised too much (I don't think), but the
+ *  internal complexity is higher than it should be for such a relatively
+ *  simple routine.
+ *
+ *  Optimization/clarity suggestions are welcome.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "replaygain_analysis.h"
+
+Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
+
+typedef unsigned short  Uint16_t;
+typedef signed short    Int16_t;
+typedef unsigned int    Uint32_t;
+typedef signed int      Int32_t;
+
+#define YULE_ORDER         10
+#define BUTTER_ORDER        2
+#define RMS_PERCENTILE      0.95        /* percentile which is louder than the proposed level */
+#define MAX_SAMP_FREQ   48000.          /* maximum allowed sample frequency [Hz] */
+#define RMS_WINDOW_TIME     0.050       /* Time slice size [s] */
+#define STEPS_per_dB      100.          /* Table entries per dB */
+#define MAX_dB            120.          /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
+
+#define MAX_ORDER               (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
+/* [JEC] the following was originally #defined as:
+ *   (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME)
+ * but that seemed to fail to take into account the ceil() part of the
+ * sampleWindow calculation in ResetSampleFrequency(), and was causing
+ * buffer overflows for 48kHz analysis, hence the +1.
+ */
+#ifndef __sun
+ #define MAX_SAMPLES_PER_WINDOW  (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.)   /* max. Samples per Time slice */
+#else
+ /* [JEC] Solaris Forte compiler doesn't like float calc in array indices */
+ #define MAX_SAMPLES_PER_WINDOW  (size_t) (2401)
+#endif
+#define PINK_REF                64.82 /* 298640883795 */                          /* calibration value */
+
+static Float_t          linprebuf [MAX_ORDER * 2];
+static Float_t*         linpre;                                          /* left input samples, with pre-buffer */
+static Float_t          lstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         lstep;                                           /* left "first step" (i.e. post first filter) samples */
+static Float_t          loutbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         lout;                                            /* left "out" (i.e. post second filter) samples */
+static Float_t          rinprebuf [MAX_ORDER * 2];
+static Float_t*         rinpre;                                          /* right input samples ... */
+static Float_t          rstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         rstep;
+static Float_t          routbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         rout;
+static unsigned int              sampleWindow;                           /* number of samples required to reach number of milliseconds required for RMS window */
+static unsigned long    totsamp;
+static double           lsum;
+static double           rsum;
+static int              freqindex;
+#ifndef __sun
+static Uint32_t  A [(size_t)(STEPS_per_dB * MAX_dB)];
+static Uint32_t  B [(size_t)(STEPS_per_dB * MAX_dB)];
+#else
+/* [JEC] Solaris Forte compiler doesn't like float calc in array indices */
+static Uint32_t  A [12000];
+static Uint32_t  B [12000];
+#endif
+
+/* for each filter:
+   [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */
+
+#ifdef WIN32
+#pragma warning ( disable : 4305 )
+#endif
+
+static const Float_t  AYule [9] [11] = {
+    { 1., -3.84664617118067,  7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294,  9.48293806319790, -5.87257861775999,  2.75465861874613, -0.86984376593551, 0.13919314567432 },
+    { 1., -3.47845948550071,  6.36317777566148, -8.54751527471874,  9.47693607801280, -8.81498681370155,  6.85401540936998, -4.39470996079559,  2.19611684890774, -0.75104302451432, 0.13149317958808 },
+    { 1., -2.37898834973084,  2.84868151156327, -2.64577170229825,  2.23697657451713, -1.67148153367602,  1.00595954808547, -0.45953458054983,  0.16378164858596, -0.05032077717131, 0.02347897407020 },
+    { 1., -1.61273165137247,  1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906,  0.39120800788284, -0.22138138954925,  0.04500235387352,  0.02005851806501, 0.00302439095741 },
+    { 1., -1.49858979367799,  0.87350271418188,  0.12205022308084, -0.80774944671438,  0.47854794562326, -0.12453458140019, -0.04067510197014,  0.08333755284107, -0.04237348025746, 0.02977207319925 },
+    { 1., -0.62820619233671,  0.29661783706366, -0.37256372942400,  0.00213767857124, -0.42029820170918,  0.22199650564824,  0.00613424350682,  0.06747620744683,  0.05784820375801, 0.03222754072173 },
+    { 1., -1.04800335126349,  0.29156311971249, -0.26806001042947,  0.00819999645858,  0.45054734505008, -0.33032403314006,  0.06739368333110, -0.04784254229033,  0.01639907836189, 0.01807364323573 },
+    { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477,  0.14728154134330,  0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053,  0.02442357316099, 0.01818801111503 },
+    { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242,  0.26408300200955,  0.15113130533216, -0.17556493366449, -0.18823009262115,  0.05477720428674, 0.04704409688120 }
+};
+
+static const Float_t  BYule [9] [11] = {
+    { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619,  0.02161526843274, -0.02074045215285,  0.00594298065125,  0.00306428023191,  0.00012025322027,  0.00288463683916 },
+    { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936,  0.02245293253339, -0.02596338512915,  0.01624864962975, -0.00240879051584,  0.00674613682247, -0.00187763777362 },
+    { 0.15457299681924, -0.09331049056315, -0.06247880153653,  0.02163541888798, -0.05588393329856,  0.04781476674921,  0.00222312597743,  0.03174092540049, -0.01390589421898,  0.00651420667831, -0.00881362733839 },
+    { 0.30296907319327, -0.22613988682123, -0.08587323730772,  0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913,  0.06276101321749, -0.00000828086748,  0.00205861885564, -0.02950134983287 },
+    { 0.33642304856132, -0.25572241425570, -0.11828570177555,  0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440,  0.05724228140351,  0.00832043980773, -0.01635381384540, -0.01760176568150 },
+    { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551,  0.04078262797139, -0.12398163381748,  0.04097565135648,  0.10478503600251, -0.01863887810927, -0.03193428438915,  0.00541907748707 },
+    { 0.56619470757641, -0.75464456939302,  0.16242137742230,  0.16744243493672, -0.18901604199609,  0.30931782841830, -0.27562961986224,  0.00647310677246,  0.08647503780351, -0.03788984554840, -0.00588215443421 },
+    { 0.58100494960553, -0.53174909058578, -0.14289799034253,  0.17520704835522,  0.02377945217615,  0.15558449135573, -0.25344790059353,  0.01628462406333,  0.06920467763959, -0.03721611395801, -0.00749618797172 },
+    { 0.53648789255105, -0.42163034350696, -0.00275953611929,  0.04267842219415, -0.10214864179676,  0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000,  0.04788665548180, -0.02217936801134 }
+};
+
+static const Float_t  AButter [9] [3] = {
+    { 1., -1.97223372919527, 0.97261396931306 },
+    { 1., -1.96977855582618, 0.97022847566350 },
+    { 1., -1.95835380975398, 0.95920349965459 },
+    { 1., -1.95002759149878, 0.95124613669835 },
+    { 1., -1.94561023566527, 0.94705070426118 },
+    { 1., -1.92783286977036, 0.93034775234268 },
+    { 1., -1.91858953033784, 0.92177618768381 },
+    { 1., -1.91542108074780, 0.91885558323625 },
+    { 1., -1.88903307939452, 0.89487434461664 }
+};
+
+static const Float_t  BButter [9] [3] = {
+    { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
+    { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
+    { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
+    { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
+    { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
+    { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
+    { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
+    { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
+    { 0.94597685600279, -1.89195371200558, 0.94597685600279 }
+};
+
+#ifdef WIN32
+#pragma warning ( default : 4305 )
+#endif
+
+/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
+
+static void
+filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order )
+{
+    double  y;
+    size_t  i;
+    size_t  k;
+
+    for ( i = 0; i < nSamples; i++ ) {
+        y = input[i] * b[0];
+        for ( k = 1; k <= order; k++ )
+            y += input[i-k] * b[k] - output[i-k] * a[k];
+        output[i] = (Float_t)y;
+    }
+}
+
+/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
+
+int
+ResetSampleFrequency ( long samplefreq ) {
+    int  i;
+
+    /* zero out initial values */
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
+
+    switch ( (int)(samplefreq) ) {
+        case 48000: freqindex = 0; break;
+        case 44100: freqindex = 1; break;
+        case 32000: freqindex = 2; break;
+        case 24000: freqindex = 3; break;
+        case 22050: freqindex = 4; break;
+        case 16000: freqindex = 5; break;
+        case 12000: freqindex = 6; break;
+        case 11025: freqindex = 7; break;
+        case  8000: freqindex = 8; break;
+        default:    return INIT_GAIN_ANALYSIS_ERROR;
+    }
+
+    sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME);
+
+    lsum         = 0.;
+    rsum         = 0.;
+    totsamp      = 0;
+
+    memset ( A, 0, sizeof(A) );
+
+       return INIT_GAIN_ANALYSIS_OK;
+}
+
+int
+InitGainAnalysis ( long samplefreq )
+{
+       if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) {
+               return INIT_GAIN_ANALYSIS_ERROR;
+       }
+
+    linpre       = linprebuf + MAX_ORDER;
+    rinpre       = rinprebuf + MAX_ORDER;
+    lstep        = lstepbuf  + MAX_ORDER;
+    rstep        = rstepbuf  + MAX_ORDER;
+    lout         = loutbuf   + MAX_ORDER;
+    rout         = routbuf   + MAX_ORDER;
+
+    memset ( B, 0, sizeof(B) );
+
+    return INIT_GAIN_ANALYSIS_OK;
+}
+
+/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
+
+int
+AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels )
+{
+    const Float_t*  curleft;
+    const Float_t*  curright;
+    long            batchsamples;
+    long            cursamples;
+    long            cursamplepos;
+    int             i;
+
+    if ( num_samples == 0 )
+        return GAIN_ANALYSIS_OK;
+
+    cursamplepos = 0;
+    batchsamples = num_samples;
+
+    switch ( num_channels) {
+    case  1: right_samples = left_samples;
+    case  2: break;
+    default: return GAIN_ANALYSIS_ERROR;
+    }
+
+    if ( num_samples < MAX_ORDER ) {
+        memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) );
+        memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) );
+    }
+    else {
+        memcpy ( linprebuf + MAX_ORDER, left_samples,  MAX_ORDER   * sizeof(Float_t) );
+        memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER   * sizeof(Float_t) );
+    }
+
+    while ( batchsamples > 0 ) {
+        cursamples = batchsamples > (long)(sampleWindow-totsamp)  ?  (long)(sampleWindow - totsamp)  :  batchsamples;
+        if ( cursamplepos < MAX_ORDER ) {
+            curleft  = linpre+cursamplepos;
+            curright = rinpre+cursamplepos;
+            if (cursamples > MAX_ORDER - cursamplepos )
+                cursamples = MAX_ORDER - cursamplepos;
+        }
+        else {
+            curleft  = left_samples  + cursamplepos;
+            curright = right_samples + cursamplepos;
+        }
+
+        filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+        filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+
+        filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+        filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+
+        for ( i = 0; i < cursamples; i++ ) {             /* Get the squared values */
+            lsum += lout [totsamp+i] * lout [totsamp+i];
+            rsum += rout [totsamp+i] * rout [totsamp+i];
+        }
+
+        batchsamples -= cursamples;
+        cursamplepos += cursamples;
+        totsamp      += cursamples;
+        if ( totsamp == sampleWindow ) {  /* Get the Root Mean Square (RMS) for this set of samples */
+            double  val  = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 );
+            int     ival = (int) val;
+            if ( ival <                     0 ) ival = 0;
+            if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1;
+            A [ival]++;
+            lsum = rsum = 0.;
+            memmove ( loutbuf , loutbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( routbuf , routbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+            totsamp = 0;
+        }
+        if ( totsamp > sampleWindow )   /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
+            return GAIN_ANALYSIS_ERROR;
+    }
+    if ( num_samples < MAX_ORDER ) {
+        memmove ( linprebuf,                           linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+        memmove ( rinprebuf,                           rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+        memcpy  ( linprebuf + MAX_ORDER - num_samples, left_samples,          num_samples             * sizeof(Float_t) );
+        memcpy  ( rinprebuf + MAX_ORDER - num_samples, right_samples,         num_samples             * sizeof(Float_t) );
+    }
+    else {
+        memcpy  ( linprebuf, left_samples  + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+        memcpy  ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+    }
+
+    return GAIN_ANALYSIS_OK;
+}
+
+
+static Float_t
+analyzeResult ( Uint32_t* Array, size_t len )
+{
+    Uint32_t  elems;
+    Int32_t   upper;
+    size_t    i;
+
+    elems = 0;
+    for ( i = 0; i < len; i++ )
+        elems += Array[i];
+    if ( elems == 0 )
+        return GAIN_NOT_ENOUGH_SAMPLES;
+
+    upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE));
+    for ( i = len; i-- > 0; ) {
+        if ( (upper -= Array[i]) <= 0 )
+            break;
+    }
+
+    return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB);
+}
+
+
+Float_t
+GetTitleGain ( void )
+{
+    Float_t  retval;
+    unsigned int    i;
+
+    retval = analyzeResult ( A, sizeof(A)/sizeof(*A) );
+
+    for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) {
+        B[i] += A[i];
+        A[i]  = 0;
+    }
+
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f;
+
+    totsamp = 0;
+    lsum    = rsum = 0.;
+    return retval;
+}
+
+
+Float_t
+GetAlbumGain ( void )
+{
+    return analyzeResult ( B, sizeof(B)/sizeof(*B) );
+}
+
+/* end of replaygain_analysis.c */
diff --git a/src/share/replaygain_analysis/replaygain_analysis_static.dsp b/src/share/replaygain_analysis/replaygain_analysis_static.dsp
new file mode 100644 (file)
index 0000000..e2dc12c
--- /dev/null
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="replaygain_analysis_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=replaygain_analysis_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "replaygain_analysis_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "replaygain_analysis_static.mak" CFG="replaygain_analysis_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "replaygain_analysis_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "replaygain_analysis_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "replaygain_analysis"\r
+# PROP Scc_LocalPath "..\..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "replaygain_analysis_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /Op /I ".\include" /I "..\..\..\include\share" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "replaygain_analysis_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\..\include\share" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "replaygain_analysis_static - Win32 Release"\r
+# Name "replaygain_analysis_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\replaygain_analysis.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\replaygain_analysis.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/share/replaygain_analysis/replaygain_analysis_static.vcproj b/src/share/replaygain_analysis/replaygain_analysis_static.vcproj
new file mode 100644 (file)
index 0000000..1d60743
--- /dev/null
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="replaygain_analysis_static"\r
+       ProjectGUID="{4cefbc89-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="replaygain_analysis_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\include\share\replaygain_analysis.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\replaygain_analysis.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/share/replaygain_synthesis/Makefile.am b/src/share/replaygain_synthesis/Makefile.am
new file mode 100644 (file)
index 0000000..4ea9e8a
--- /dev/null
@@ -0,0 +1,22 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = include .
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/include/share
+
+noinst_LTLIBRARIES = libreplaygain_synthesis.la
+
+libreplaygain_synthesis_la_SOURCES = replaygain_synthesis.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       replaygain_synthesis_static.dsp \
+       replaygain_synthesis_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/share/replaygain_synthesis/Makefile.lite b/src/share/replaygain_synthesis/Makefile.lite
new file mode 100644 (file)
index 0000000..e58e708
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libreplaygain_synthesis
+INCLUDES = -I./include -I$(topdir)/include -I$(topdir)/include/share
+
+SRCS_C = \
+       replaygain_synthesis.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/replaygain_synthesis/include/Makefile.am b/src/share/replaygain_synthesis/include/Makefile.am
new file mode 100644 (file)
index 0000000..4418640
--- /dev/null
@@ -0,0 +1,18 @@
+#  replaygain_synthesis - Routines for applying ReplayGain to a signal
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+# 
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+SUBDIRS = private
diff --git a/src/share/replaygain_synthesis/include/private/Makefile.am b/src/share/replaygain_synthesis/include/private/Makefile.am
new file mode 100644 (file)
index 0000000..081d7ba
--- /dev/null
@@ -0,0 +1,19 @@
+#  replaygain_synthesis - Routines for applying ReplayGain to a signal
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+# 
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library 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
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+noinst_HEADERS = \
+       fast_float_math_hack.h
diff --git a/src/share/replaygain_synthesis/include/private/fast_float_math_hack.h b/src/share/replaygain_synthesis/include/private/fast_float_math_hack.h
new file mode 100644 (file)
index 0000000..d8608fc
--- /dev/null
@@ -0,0 +1,39 @@
+#   ifdef __ICL /* only Intel C compiler has fmath ??? */
+
+    #include <mathf.h>
+
+/* Nearest integer, absolute value, etc. */
+
+    #define ceil ceilf
+    #define fabs fabsf
+    #define floor floorf
+    #define fmod fmodf
+    #define rint rintf
+    #define hypot hypotf
+
+/* Power functions */
+
+    #define pow powf
+    #define sqrt sqrtf
+
+/* Exponential and logarithmic functions */
+
+    #define exp expf
+    #define log logf
+    #define log10 log10f
+
+/* Trigonometric functions */
+
+    #define acos acosf
+    #define asin asinf
+    #define atan atanf
+    #define cos cosf
+    #define sin sinf
+    #define tan tanf
+
+/* Hyperbolic functions */
+    #define cosh coshf
+    #define sinh sinhf
+    #define tanh tanhf
+
+#   endif
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis.c b/src/share/replaygain_synthesis/replaygain_synthesis.c
new file mode 100644 (file)
index 0000000..e561576
--- /dev/null
@@ -0,0 +1,467 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+/*
+ * This is an aggregation of pieces of code from John Edwards' WaveGain
+ * program.  Mostly cosmetic changes were made; otherwise, the dithering
+ * code is almost untouched and the gain processing was converted from
+ * processing a whole file to processing chunks of samples.
+ *
+ * The original copyright notices for WaveGain's dither.c and wavegain.c
+ * appear below:
+ */
+/*
+ * (c) 2002 John Edwards
+ * mostly lifted from work by Frank Klemm
+ * random functions for dithering.
+ */
+/*
+ * Copyright (C) 2002 John Edwards
+ * Additional code by Magnus Holmgren and Gian-Carlo Pascutto
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include <math.h>
+#include "private/fast_float_math_hack.h"
+#include "replaygain_synthesis.h"
+#include "FLAC/assert.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/* adjust for compilers that can't understand using LL suffix for int64_t literals */
+#ifdef _MSC_VER
+#define FLAC__I64L(x) x
+#else
+#define FLAC__I64L(x) x##LL
+#endif
+
+
+/*
+ * the following is based on parts of dither.c
+ */
+
+
+/*
+ *  This is a simple random number generator with good quality for audio purposes.
+ *  It consists of two polycounters with opposite rotation direction and different
+ *  periods. The periods are coprime, so the total period is the product of both.
+ *
+ *     -------------------------------------------------------------------------------------------------
+ * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0|
+ * |   -------------------------------------------------------------------------------------------------
+ * |                                                                          |  |  |  |     |        |
+ * |                                                                          +--+--+--+-XOR-+--------+
+ * |                                                                                      |
+ * +--------------------------------------------------------------------------------------+
+ *
+ *     -------------------------------------------------------------------------------------------------
+ *     |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+
+ *     -------------------------------------------------------------------------------------------------   |
+ *       |  |           |  |                                                                               |
+ *       +--+----XOR----+--+                                                                               |
+ *                |                                                                                        |
+ *                +----------------------------------------------------------------------------------------+
+ *
+ *
+ *  The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481,
+ *  which gives a period of 18.410.713.077.675.721.215. The result is the
+ *  XORed values of both generators.
+ */
+
+static unsigned int random_int_(void)
+{
+       static const unsigned char parity_[256] = {
+               0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+               1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+               1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+               0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+               1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+               0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+               0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+               1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+       };
+       static unsigned int r1_ = 1;
+       static unsigned int r2_ = 1;
+
+       unsigned int t1, t2, t3, t4;
+
+       /* Parity calculation is done via table lookup, this is also available
+        * on CPUs without parity, can be implemented in C and avoid unpredictable
+        * jumps and slow rotate through the carry flag operations.
+        */
+       t3   = t1 = r1_;    t4   = t2 = r2_;
+       t1  &= 0xF5;        t2 >>= 25;
+       t1   = parity_[t1]; t2  &= 0x63;
+       t1 <<= 31;          t2   = parity_[t2];
+
+       return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 );
+}
+
+/* gives a equal distributed random number */
+/* between -2^31*mult and +2^31*mult */
+static double random_equi_(double mult)
+{
+       return mult * (int) random_int_();
+}
+
+/* gives a triangular distributed random number */
+/* between -2^32*mult and +2^32*mult */
+static double random_triangular_(double mult)
+{
+       return mult * ( (double) (int) random_int_() + (double) (int) random_int_() );
+}
+
+
+static const float  F44_0 [16 + 32] = {
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+       (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0
+};
+
+
+static const float  F44_1 [16 + 32] = {  /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */
+       (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+       (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+       (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+       (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+       (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+       (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+       (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+       (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+       (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+       (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+       (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+       (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+};
+
+
+static const float  F44_2 [16 + 32] = {  /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */
+       (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+       (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+       (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+       (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+       (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+       (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+       (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+       (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+       (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+       (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+       (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+       (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+};
+
+
+static const float  F44_3 [16 + 32] = {  /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */
+       (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+       (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+       (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+       (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+       (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+       (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+       (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+       (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+       (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+       (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+       (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+       (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099
+};
+
+
+static double scalar16_(const float* x, const float* y)
+{
+       return
+               x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] +
+               x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] +
+               x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] +
+               x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15];
+}
+
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype)
+{
+       static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67,  0,  0 };
+       static const float*               F [] = { F44_0, F44_1, F44_2, F44_3 };
+
+       int index;
+
+       if (shapingtype < 0) shapingtype = 0;
+       if (shapingtype > 3) shapingtype = 3;
+       d->ShapingType = (NoiseShaping)shapingtype;
+       index = bits - 11 - shapingtype;
+       if (index < 0) index = 0;
+       if (index > 9) index = 9;
+
+       memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) );
+       memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) );
+
+       d->FilterCoeff = F [shapingtype];
+       d->Mask   = ((FLAC__uint64)-1) << (32 - bits);
+       d->Add    = 0.5     * ((1L << (32 - bits)) - 1);
+       d->Dither = 0.01f*default_dither[index] / (((FLAC__int64)1) << bits);
+       d->LastHistoryIndex = 0;
+}
+
+/*
+ * the following is based on parts of wavegain.c
+ */
+
+static FLaC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
+{
+       union {
+               double d;
+               FLAC__int64 i;
+       } doubletmp;
+       double Sum2;
+       FLAC__int64 val;
+
+#define ROUND64(x)   ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) )
+
+       if(do_dithering) {
+               if(shapingtype == 0) {
+                       double  tmp = random_equi_(d->Dither);
+                       Sum2 = tmp - d->LastRandomNumber [k];
+                       d->LastRandomNumber [k] = (int)tmp;
+                       Sum2 = Sum += Sum2;
+                       val = ROUND64(Sum2) & d->Mask;
+               }
+               else {
+                       Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i);
+                       Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2;
+                       Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i);
+                       val = ROUND64(Sum2) & d->Mask;
+                       d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
+               }
+               return val;
+       }
+       else
+               return ROUND64(Sum);
+
+#undef ROUND64
+}
+
+#if 0
+       float        peak = 0.f,
+                    new_peak,
+                    factor_clip
+       double       scale,
+                    dB;
+
+       ...
+
+       peak is in the range -32768.0 .. 32767.0
+
+       /* calculate factors for ReplayGain and ClippingPrevention */
+       *track_gain = GetTitleGain() + settings->man_gain;
+       scale = (float) pow(10., *track_gain * 0.05);
+       if(settings->clip_prev) {
+               factor_clip  = (float) (32767./( peak + 1));
+               if(scale < factor_clip)
+                       factor_clip = 1.f;
+               else
+                       factor_clip /= scale;
+               scale *= factor_clip;
+       }
+       new_peak = (float) peak * scale;
+
+       dB = 20. * log10(scale);
+       *track_gain = (float) dB;
+
+       const double scale = pow(10., (double)gain * 0.05);
+#endif
+
+
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
+{
+       static const FLAC__int32 conv_factors_[33] = {
+               -1, /* 0 bits-per-sample (not supported) */
+               -1, /* 1 bits-per-sample (not supported) */
+               -1, /* 2 bits-per-sample (not supported) */
+               -1, /* 3 bits-per-sample (not supported) */
+               268435456, /* 4 bits-per-sample */
+               134217728, /* 5 bits-per-sample */
+               67108864, /* 6 bits-per-sample */
+               33554432, /* 7 bits-per-sample */
+               16777216, /* 8 bits-per-sample */
+               8388608, /* 9 bits-per-sample */
+               4194304, /* 10 bits-per-sample */
+               2097152, /* 11 bits-per-sample */
+               1048576, /* 12 bits-per-sample */
+               524288, /* 13 bits-per-sample */
+               262144, /* 14 bits-per-sample */
+               131072, /* 15 bits-per-sample */
+               65536, /* 16 bits-per-sample */
+               32768, /* 17 bits-per-sample */
+               16384, /* 18 bits-per-sample */
+               8192, /* 19 bits-per-sample */
+               4096, /* 20 bits-per-sample */
+               2048, /* 21 bits-per-sample */
+               1024, /* 22 bits-per-sample */
+               512, /* 23 bits-per-sample */
+               256, /* 24 bits-per-sample */
+               128, /* 25 bits-per-sample */
+               64, /* 26 bits-per-sample */
+               32, /* 27 bits-per-sample */
+               16, /* 28 bits-per-sample */
+               8, /* 29 bits-per-sample */
+               4, /* 30 bits-per-sample */
+               2, /* 31 bits-per-sample */
+               1 /* 32 bits-per-sample */
+       };
+       static const FLAC__int64 hard_clip_factors_[33] = {
+               0, /* 0 bits-per-sample (not supported) */
+               0, /* 1 bits-per-sample (not supported) */
+               0, /* 2 bits-per-sample (not supported) */
+               0, /* 3 bits-per-sample (not supported) */
+               -8, /* 4 bits-per-sample */
+               -16, /* 5 bits-per-sample */
+               -32, /* 6 bits-per-sample */
+               -64, /* 7 bits-per-sample */
+               -128, /* 8 bits-per-sample */
+               -256, /* 9 bits-per-sample */
+               -512, /* 10 bits-per-sample */
+               -1024, /* 11 bits-per-sample */
+               -2048, /* 12 bits-per-sample */
+               -4096, /* 13 bits-per-sample */
+               -8192, /* 14 bits-per-sample */
+               -16384, /* 15 bits-per-sample */
+               -32768, /* 16 bits-per-sample */
+               -65536, /* 17 bits-per-sample */
+               -131072, /* 18 bits-per-sample */
+               -262144, /* 19 bits-per-sample */
+               -524288, /* 20 bits-per-sample */
+               -1048576, /* 21 bits-per-sample */
+               -2097152, /* 22 bits-per-sample */
+               -4194304, /* 23 bits-per-sample */
+               -8388608, /* 24 bits-per-sample */
+               -16777216, /* 25 bits-per-sample */
+               -33554432, /* 26 bits-per-sample */
+               -67108864, /* 27 bits-per-sample */
+               -134217728, /* 28 bits-per-sample */
+               -268435456, /* 29 bits-per-sample */
+               -536870912, /* 30 bits-per-sample */
+               -1073741824, /* 31 bits-per-sample */
+               (FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */
+       };
+       const FLAC__int32 conv_factor = conv_factors_[target_bps];
+       const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps];
+       /*
+        * The integer input coming in has a varying range based on the
+        * source_bps.  We want to normalize it to [-1.0, 1.0) so instead
+        * of doing two multiplies on each sample, we just multiple
+        * 'scale' by 1/(2^(source_bps-1))
+        */
+       const double multi_scale = scale / (double)(1u << (source_bps-1));
+
+       FLAC__byte * const start = data_out;
+       unsigned i, channel;
+       const FLAC__int32 *input_;
+       double sample;
+       const unsigned bytes_per_sample = target_bps / 8;
+       const unsigned last_history_index = dither_context->LastHistoryIndex;
+       NoiseShaping noise_shaping = dither_context->ShapingType;
+       FLAC__int64 val64;
+       FLAC__int32 val32;
+       FLAC__int32 uval32;
+       const FLAC__uint32 twiggle = 1u << (target_bps - 1);
+
+       FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS);
+       FLAC__ASSERT(source_bps >= 4);
+       FLAC__ASSERT(target_bps >= 4);
+       FLAC__ASSERT(source_bps <= 32);
+       FLAC__ASSERT(target_bps < 32);
+       FLAC__ASSERT((target_bps & 7) == 0);
+
+       for(channel = 0; channel < channels; channel++) {
+               const unsigned incr = bytes_per_sample * channels;
+               data_out = start + bytes_per_sample * channel;
+               input_ = input[channel];
+               for(i = 0; i < wide_samples; i++, data_out += incr) {
+                       sample = (double)input_[i] * multi_scale;
+
+                       if(hard_limit) {
+                               /* hard 6dB limiting */
+                               if(sample < -0.5)
+                                       sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
+                               else if(sample > 0.5)
+                                       sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
+                       }
+                       sample *= 2147483647.f;
+
+                       val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor;
+
+                       val32 = (FLAC__int32)val64;
+                       if(val64 >= -hard_clip_factor)
+                               val32 = (FLAC__int32)(-(hard_clip_factor+1));
+                       else if(val64 < hard_clip_factor)
+                               val32 = (FLAC__int32)hard_clip_factor;
+
+                       uval32 = (FLAC__uint32)val32;
+                       if (unsigned_data_out)
+                               uval32 ^= twiggle;
+
+                       if (little_endian_data_out) {
+                               switch(target_bps) {
+                                       case 24:
+                                               data_out[2] = (FLAC__byte)(uval32 >> 16);
+                                               /* fall through */
+                                       case 16:
+                                               data_out[1] = (FLAC__byte)(uval32 >> 8);
+                                               /* fall through */
+                                       case 8:
+                                               data_out[0] = (FLAC__byte)uval32;
+                                               break;
+                               }
+                       }
+                       else {
+                               switch(target_bps) {
+                                       case 24:
+                                               data_out[0] = (FLAC__byte)(uval32 >> 16);
+                                               data_out[1] = (FLAC__byte)(uval32 >> 8);
+                                               data_out[2] = (FLAC__byte)uval32;
+                                               break;
+                                       case 16:
+                                               data_out[0] = (FLAC__byte)(uval32 >> 8);
+                                               data_out[1] = (FLAC__byte)uval32;
+                                               break;
+                                       case 8:
+                                               data_out[0] = (FLAC__byte)uval32;
+                                               break;
+                               }
+                       }
+               }
+       }
+       dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32;
+
+       return wide_samples * channels * (target_bps/8);
+}
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis_static.dsp b/src/share/replaygain_synthesis/replaygain_synthesis_static.dsp
new file mode 100644 (file)
index 0000000..9c64432
--- /dev/null
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="replaygain_synthesis_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=replaygain_synthesis_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "replaygain_synthesis_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "replaygain_synthesis_static.mak" CFG="replaygain_synthesis_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "replaygain_synthesis_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "replaygain_synthesis_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "replaygain_synthesis"\r
+# PROP Scc_LocalPath "..\..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "replaygain_synthesis_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /Op /I ".\include" /I "..\..\..\include" /I "..\..\..\include\share" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "replaygain_synthesis_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\..\include" /I "..\..\..\include\share" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "replaygain_synthesis_static - Win32 Release"\r
+# Name "replaygain_synthesis_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\replaygain_synthesis.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\include\private\fast_float_math_hack.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\replaygain_synthesis.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj b/src/share/replaygain_synthesis/replaygain_synthesis_static.vcproj
new file mode 100644 (file)
index 0000000..841b0ec
--- /dev/null
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="replaygain_synthesis_static"\r
+       ProjectGUID="{4cefbc8a-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="replaygain_synthesis_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\include\private\fast_float_math_hack.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\include\share\replaygain_synthesis.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\replaygain_synthesis.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/share/utf8/Makefile.am b/src/share/utf8/Makefile.am
new file mode 100644 (file)
index 0000000..bc42c2d
--- /dev/null
@@ -0,0 +1,25 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/include/share
+
+noinst_LTLIBRARIES = libutf8.la
+
+libutf8_la_SOURCES = charset.c charset.h iconvert.c utf8.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       charmaps.h \
+       makemap.c \
+       charset_test.c \
+       charsetmap.h \
+       iconvert.h \
+       utf8_static.dsp \
+       utf8_static.vcproj
+
+debug:
+       $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+       $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/share/utf8/Makefile.lite b/src/share/utf8/Makefile.lite
new file mode 100644 (file)
index 0000000..95e4a7f
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# GNU makefile
+#
+
+topdir = ../../..
+
+LIB_NAME = libutf8
+INCLUDES = -I$(topdir)/include -I$(topdir)/include/share
+
+SRCS_C = \
+       charset.c \
+       iconvert.c \
+       utf8.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/share/utf8/charmaps.h b/src/share/utf8/charmaps.h
new file mode 100644 (file)
index 0000000..690d890
--- /dev/null
@@ -0,0 +1,57 @@
+
+/*
+ * If you need to generate more maps, use makemap.c on a system
+ * with a decent iconv.
+ */
+
+static const unsigned short mapping_iso_8859_2[256] = {
+  0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+  0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+  0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+  0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+  0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+  0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+  0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+  0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+  0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+  0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+  0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+  0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+  0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+  0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+  0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+  0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+  0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+  0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+  0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+  0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+  0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7,
+  0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
+  0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7,
+  0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
+  0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+  0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+  0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+  0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+  0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+  0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+  0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+  0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
+};
+
+static struct {
+  const char *name;
+  const unsigned short *map;
+  struct charset *charset;
+} maps[] = {
+  { "ISO-8859-2", mapping_iso_8859_2, 0 },
+  { 0, 0, 0 }
+};
+
+static const struct {
+  const char *bad;
+  const char *good;
+} names[] = {
+  { "ANSI_X3.4-1968", "us-ascii" },
+  { 0, 0 }
+};
diff --git a/src/share/utf8/charset.c b/src/share/utf8/charset.c
new file mode 100644 (file)
index 0000000..dcef6fc
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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
+ */
+
+/*
+ * See the corresponding header file for a description of the functions
+ * that this file provides.
+ *
+ * This was first written for Ogg Vorbis but could be of general use.
+ *
+ * The only deliberate assumption about data sizes is that a short has
+ * at least 16 bits, but this code has only been tested on systems with
+ * 8-bit char, 16-bit short and 32-bit int.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+
+#include <stdlib.h>
+
+#include "share/alloc.h"
+#include "charset.h"
+
+#include "charmaps.h"
+
+/*
+ * This is like the standard strcasecmp, but it does not depend
+ * on the locale. Locale-dependent functions can be dangerous:
+ * we once had a bug involving strcasecmp("iso", "ISO") in a
+ * Turkish locale!
+ *
+ * (I'm not really sure what the official standard says
+ * about the sign of strcasecmp("Z", "["), but usually
+ * we're only interested in whether it's zero.)
+ */
+
+static int ascii_strcasecmp(const char *s1, const char *s2)
+{
+  char c1, c2;
+
+  for (;; s1++, s2++) {
+    if (!*s1 || !*s1)
+      break;
+    if (*s1 == *s2)
+      continue;
+    c1 = *s1;
+    if ('a' <= c1 && c1 <= 'z')
+      c1 += 'A' - 'a';
+    c2 = *s2;
+    if ('a' <= c2 && c2 <= 'z')
+      c2 += 'A' - 'a';
+    if (c1 != c2)
+      break;
+  }
+  return (unsigned char)*s1 - (unsigned char)*s2;
+}
+
+/*
+ * UTF-8 equivalents of the C library's wctomb() and mbtowc().
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n)
+{
+  unsigned char c;
+  int wc, i, k;
+
+  if (!n || !s)
+    return 0;
+
+  c = *s;
+  if (c < 0x80) {
+    if (pwc)
+      *pwc = c;
+    return c ? 1 : 0;
+  }
+  else if (c < 0xc2)
+    return -1;
+  else if (c < 0xe0) {
+    if (n >= 2 && (s[1] & 0xc0) == 0x80) {
+      if (pwc)
+       *pwc = ((c & 0x1f) << 6) | (s[1] & 0x3f);
+      return 2;
+    }
+    else
+      return -1;
+  }
+  else if (c < 0xf0)
+    k = 3;
+  else if (c < 0xf8)
+    k = 4;
+  else if (c < 0xfc)
+    k = 5;
+  else if (c < 0xfe)
+    k = 6;
+  else
+    return -1;
+
+  if (n < (size_t)k)
+    return -1;
+  wc = *s++ & ((1 << (7 - k)) - 1);
+  for (i = 1; i < k; i++) {
+    if ((*s & 0xc0) != 0x80)
+      return -1;
+    wc = (wc << 6) | (*s++ & 0x3f);
+  }
+  if (wc < (1 << (5 * k - 4)))
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return k;
+}
+
+int utf8_wctomb(char *s, int wc1)
+{
+  unsigned int wc = wc1;
+
+  if (!s)
+    return 0;
+  if (wc < (1u << 7)) {
+    *s++ = wc;
+    return 1;
+  }
+  else if (wc < (1u << 11)) {
+    *s++ = 0xc0 | (wc >> 6);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 2;
+  }
+  else if (wc < (1u << 16)) {
+    *s++ = 0xe0 | (wc >> 12);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 3;
+  }
+  else if (wc < (1u << 21)) {
+    *s++ = 0xf0 | (wc >> 18);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 4;
+  }
+  else if (wc < (1u << 26)) {
+    *s++ = 0xf8 | (wc >> 24);
+    *s++ = 0x80 | ((wc >> 18) & 0x3f);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 5;
+  }
+  else if (wc < (1u << 31)) {
+    *s++ = 0xfc | (wc >> 30);
+    *s++ = 0x80 | ((wc >> 24) & 0x3f);
+    *s++ = 0x80 | ((wc >> 18) & 0x3f);
+    *s++ = 0x80 | ((wc >> 12) & 0x3f);
+    *s++ = 0x80 | ((wc >> 6) & 0x3f);
+    *s++ = 0x80 | (wc & 0x3f);
+    return 6;
+  }
+  else
+    return -1;
+}
+
+/*
+ * The charset "object" and methods.
+ */
+
+struct charset {
+  int max;
+  int (*mbtowc)(void *table, int *pwc, const char *s, size_t n);
+  int (*wctomb)(void *table, char *s, int wc);
+  void *map;
+};
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n)
+{
+  return (*charset->mbtowc)(charset->map, pwc, s, n);
+}
+
+int charset_wctomb(struct charset *charset, char *s, int wc)
+{
+  return (*charset->wctomb)(charset->map, s, wc);
+}
+
+int charset_max(struct charset *charset)
+{
+  return charset->max;
+}
+
+/*
+ * Implementation of UTF-8.
+ */
+
+static int mbtowc_utf8(void *map, int *pwc, const char *s, size_t n)
+{
+  (void)map;
+  return utf8_mbtowc(pwc, s, n);
+}
+
+static int wctomb_utf8(void *map, char *s, int wc)
+{
+  (void)map;
+  return utf8_wctomb(s, wc);
+}
+
+/*
+ * Implementation of US-ASCII.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_ascii(void *map, int *pwc, const char *s, size_t n)
+{
+  int wc;
+
+  (void)map;
+  if (!n || !s)
+    return 0;
+  wc = (unsigned char)*s;
+  if (wc & ~0x7f)
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return wc ? 1 : 0;
+}
+
+static int wctomb_ascii(void *map, char *s, int wc)
+{
+  (void)map;
+  if (!s)
+    return 0;
+  if (wc & ~0x7f)
+    return -1;
+  *s = wc;
+  return 1;
+}
+
+/*
+ * Implementation of ISO-8859-1.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_iso1(void *map, int *pwc, const char *s, size_t n)
+{
+  int wc;
+
+  (void)map;
+  if (!n || !s)
+    return 0;
+  wc = (unsigned char)*s;
+  if (wc & ~0xff)
+    return -1;
+  if (pwc)
+    *pwc = wc;
+  return wc ? 1 : 0;
+}
+
+static int wctomb_iso1(void *map, char *s, int wc)
+{
+  (void)map;
+  if (!s)
+    return 0;
+  if (wc & ~0xff)
+    return -1;
+  *s = wc;
+  return 1;
+}
+
+/*
+ * Implementation of any 8-bit charset.
+ */
+
+struct map {
+  const unsigned short *from;
+  struct inverse_map *to;
+};
+
+static int mbtowc_8bit(void *map1, int *pwc, const char *s, size_t n)
+{
+  struct map *map = map1;
+  unsigned short wc;
+
+  if (!n || !s)
+    return 0;
+  wc = map->from[(unsigned char)*s];
+  if (wc == 0xffff)
+    return -1;
+  if (pwc)
+    *pwc = (int)wc;
+  return wc ? 1 : 0;
+}
+
+/*
+ * For the inverse map we use a hash table, which has the advantages
+ * of small constant memory requirement and simple memory allocation,
+ * but the disadvantage of slow conversion in the worst case.
+ * If you need real-time performance while letting a potentially
+ * malicious user define their own map, then the method used in
+ * linux/drivers/char/consolemap.c would be more appropriate.
+ */
+
+struct inverse_map {
+  unsigned char first[256];
+  unsigned char next[256];
+};
+
+/*
+ * The simple hash is good enough for this application.
+ * Use the alternative trivial hashes for testing.
+ */
+#define HASH(i) ((i) & 0xff)
+/* #define HASH(i) 0 */
+/* #define HASH(i) 99 */
+
+static struct inverse_map *make_inverse_map(const unsigned short *from)
+{
+  struct inverse_map *to;
+  char used[256];
+  int i, j, k;
+
+  to = (struct inverse_map *)malloc(sizeof(struct inverse_map));
+  if (!to)
+    return 0;
+  for (i = 0; i < 256; i++)
+    to->first[i] = to->next[i] = used[i] = 0;
+  for (i = 255; i >= 0; i--)
+    if (from[i] != 0xffff) {
+      k = HASH(from[i]);
+      to->next[i] = to->first[k];
+      to->first[k] = i;
+      used[k] = 1;
+    }
+
+  /* Point the empty buckets at an empty list. */
+  for (i = 0; i < 256; i++)
+    if (!to->next[i])
+      break;
+  if (i < 256)
+    for (j = 0; j < 256; j++)
+      if (!used[j])
+       to->first[j] = i;
+
+  return to;
+}
+
+int wctomb_8bit(void *map1, char *s, int wc1)
+{
+  struct map *map = map1;
+  unsigned short wc = wc1;
+  int i;
+
+  if (!s)
+    return 0;
+
+  if (wc1 & ~0xffff)
+    return -1;
+
+  if (1) /* Change 1 to 0 to test the case where malloc fails. */
+    if (!map->to)
+      map->to = make_inverse_map(map->from);
+
+  if (map->to) {
+    /* Use the inverse map. */
+    i = map->to->first[HASH(wc)];
+    for (;;) {
+      if (map->from[i] == wc) {
+       *s = i;
+       return 1;
+      }
+      if (!(i = map->to->next[i]))
+       break;
+    }
+  }
+  else {
+    /* We don't have an inverse map, so do a linear search. */
+    for (i = 0; i < 256; i++)
+      if (map->from[i] == wc) {
+       *s = i;
+       return 1;
+      }
+  }
+
+  return -1;
+}
+
+/*
+ * The "constructor" charset_find().
+ */
+
+struct charset charset_utf8 = {
+  6,
+  &mbtowc_utf8,
+  &wctomb_utf8,
+  0
+};
+
+struct charset charset_iso1 = {
+  1,
+  &mbtowc_iso1,
+  &wctomb_iso1,
+  0
+};
+
+struct charset charset_ascii = {
+  1,
+  &mbtowc_ascii,
+  &wctomb_ascii,
+  0
+};
+
+struct charset *charset_find(const char *code)
+{
+  int i;
+
+  /* Find good (MIME) name. */
+  for (i = 0; names[i].bad; i++)
+    if (!ascii_strcasecmp(code, names[i].bad)) {
+      code = names[i].good;
+      break;
+    }
+
+  /* Recognise some charsets for which we avoid using a table. */
+  if (!ascii_strcasecmp(code, "UTF-8"))
+    return &charset_utf8;
+  if (!ascii_strcasecmp(code, "US-ASCII"))
+    return &charset_ascii;
+  if (!ascii_strcasecmp(code, "ISO-8859-1"))
+    return &charset_iso1;
+
+  /* Look for a mapping for a simple 8-bit encoding. */
+  for (i = 0; maps[i].name; i++)
+    if (!ascii_strcasecmp(code, maps[i].name)) {
+      if (!maps[i].charset) {
+       maps[i].charset = (struct charset *)malloc(sizeof(struct charset));
+       if (maps[i].charset) {
+         struct map *map = (struct map *)malloc(sizeof(struct map));
+         if (!map) {
+           free(maps[i].charset);
+           maps[i].charset = 0;
+         }
+         else {
+           maps[i].charset->max = 1;
+           maps[i].charset->mbtowc = &mbtowc_8bit;
+           maps[i].charset->wctomb = &wctomb_8bit;
+           maps[i].charset->map = map;
+           map->from = maps[i].map;
+           map->to = 0; /* inverse mapping is created when required */
+         }
+       }
+      }
+      return maps[i].charset;
+    }
+
+  return 0;
+}
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero, if the result is not needed.
+ * The output buffer is null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+                   const char *from, size_t fromlen,
+                   char **to, size_t *tolen)
+{
+  int ret = 0;
+  struct charset *charset1, *charset2;
+  char *tobuf, *p, *newbuf;
+  int i, j, wc;
+
+  charset1 = charset_find(fromcode);
+  charset2 = charset_find(tocode);
+  if (!charset1 || !charset2 )
+    return -1;
+
+  tobuf = (char *)safe_malloc_mul2add_(fromlen, /*times*/charset2->max, /*+*/1);
+  if (!tobuf)
+    return -2;
+
+  for (p = tobuf; fromlen; from += i, fromlen -= i, p += j) {
+    i = charset_mbtowc(charset1, &wc, from, fromlen);
+    if (!i)
+      i = 1;
+    else if (i == -1) {
+      i  = 1;
+      wc = '#';
+      ret = 2;
+    }
+    j = charset_wctomb(charset2, p, wc);
+    if (j == -1) {
+      if (!ret)
+       ret = 1;
+      j = charset_wctomb(charset2, p, '?');
+      if (j == -1)
+       j = 0;
+    }
+  }
+
+  if (tolen)
+    *tolen = p - tobuf;
+  *p++ = '\0';
+  if (to) {
+    newbuf = realloc(tobuf, p - tobuf);
+    *to = newbuf ? newbuf : tobuf;
+  }
+  else
+    free(tobuf);
+
+  return ret;
+}
+
+#endif /* USE_CHARSET_ICONV */
diff --git a/src/share/utf8/charset.h b/src/share/utf8/charset.h
new file mode 100644 (file)
index 0000000..b5e2fb7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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 <stdlib.h>
+
+/*
+ * These functions are like the C library's mbtowc() and wctomb(),
+ * but instead of depending on the locale they always work in UTF-8,
+ * and they use int instead of wchar_t.
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n);
+int utf8_wctomb(char *s, int wc);
+
+/*
+ * This is an object-oriented version of mbtowc() and wctomb().
+ * The caller first uses charset_find() to get a pointer to struct
+ * charset, then uses the mbtowc() and wctomb() methods on it.
+ * The function charset_max() gives the maximum length of a
+ * multibyte character in that encoding.
+ * This API is only appropriate for stateless encodings like UTF-8
+ * or ISO-8859-3, but I have no intention of implementing anything
+ * other than UTF-8 and 8-bit encodings.
+ *
+ * MINOR BUG: If there is no memory charset_find() may return 0 and
+ * there is no way to distinguish this case from an unknown encoding.
+ */
+
+struct charset;
+
+struct charset *charset_find(const char *code);
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n);
+int charset_wctomb(struct charset *charset, char *s, int wc);
+int charset_max(struct charset *charset);
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero if the result is not wanted.
+ * The input or output may contain null bytes, but the output
+ * buffer is also null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ *
+ * Return value:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+                   const char *from, size_t fromlen,
+                   char **to, size_t *tolen);
diff --git a/src/share/utf8/charset_test.c b/src/share/utf8/charset_test.c
new file mode 100644 (file)
index 0000000..1d5bf71
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "charset.h"
+
+void test_any(struct charset *charset)
+{
+  int wc;
+  char s[2];
+
+  assert(charset);
+
+  /* Decoder */
+
+  assert(charset_mbtowc(charset, 0, 0, 0) == 0);
+  assert(charset_mbtowc(charset, 0, 0, 1) == 0);
+  assert(charset_mbtowc(charset, 0, (char *)(-1), 0) == 0);
+
+  assert(charset_mbtowc(charset, 0, "a", 0) == 0);
+  assert(charset_mbtowc(charset, 0, "", 1) == 0);
+  assert(charset_mbtowc(charset, 0, "b", 1) == 1);
+  assert(charset_mbtowc(charset, 0, "", 2) == 0);
+  assert(charset_mbtowc(charset, 0, "c", 2) == 1);
+
+  wc = 'x';
+  assert(charset_mbtowc(charset, &wc, "a", 0) == 0 && wc == 'x');
+  assert(charset_mbtowc(charset, &wc, "", 1) == 0 && wc == 0);
+  assert(charset_mbtowc(charset, &wc, "b", 1) == 1 && wc == 'b');
+  assert(charset_mbtowc(charset, &wc, "", 2) == 0 && wc == 0);
+  assert(charset_mbtowc(charset, &wc, "c", 2) == 1 && wc == 'c');
+
+  /* Encoder */
+
+  assert(charset_wctomb(charset, 0, 0) == 0);
+
+  s[0] = s[1] = '.';
+  assert(charset_wctomb(charset, s, 0) == 1 &&
+        s[0] == '\0' && s[1] == '.');
+  assert(charset_wctomb(charset, s, 'x') == 1 &&
+        s[0] == 'x' && s[1] == '.');
+}
+
+void test_utf8()
+{
+  struct charset *charset;
+  int wc;
+  char s[8];
+
+  charset = charset_find("UTF-8");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\177", 1) == 1 && wc == 127);
+  assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\301\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 1) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 2) == 2 && wc == 128);
+  assert(charset_mbtowc(charset, &wc, "\302\200", 3) == 2 && wc == 128);
+  assert(charset_mbtowc(charset, &wc, "\340\237\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\200", 9) == 3 &&
+        wc == 1 << 11);
+  assert(charset_mbtowc(charset, &wc, "\360\217\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\200", 9) == 4 &&
+        wc == 1 << 16);
+  assert(charset_mbtowc(charset, &wc, "\370\207\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\370\210\200\200\200", 9) == 5 &&
+        wc == 1 << 21);
+  assert(charset_mbtowc(charset, &wc, "\374\203\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\374\204\200\200\200\200", 9) == 6 &&
+        wc == 1 << 26);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\277", 9) == 6 &&
+        wc == 0x7fffffff);
+
+  assert(charset_mbtowc(charset, &wc, "\302\000", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\302\300", 2) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\040\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\340\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\000", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\340\240\300", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\020\200\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\320\200\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\000\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\300\200", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\000", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\360\220\200\300", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\077\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\377\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\077\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\377\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\077\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\377\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\077", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\377", 9) == -1);
+
+  assert(charset_mbtowc(charset, &wc, "\376\277\277\277\277\277", 9) == -1);
+  assert(charset_mbtowc(charset, &wc, "\377\277\277\277\277\277", 9) == -1);
+
+  /* Encoder */
+  strcpy(s, ".......");
+  assert(charset_wctomb(charset, s, 1 << 31) == -1 &&
+        !strcmp(s, "......."));
+  assert(charset_wctomb(charset, s, 127) == 1 &&
+        !strcmp(s, "\177......"));
+  assert(charset_wctomb(charset, s, 128) == 2 &&
+        !strcmp(s, "\302\200....."));
+  assert(charset_wctomb(charset, s, 0x7ff) == 2 &&
+        !strcmp(s, "\337\277....."));
+  assert(charset_wctomb(charset, s, 0x800) == 3 &&
+        !strcmp(s, "\340\240\200...."));
+  assert(charset_wctomb(charset, s, 0xffff) == 3 &&
+        !strcmp(s, "\357\277\277...."));
+  assert(charset_wctomb(charset, s, 0x10000) == 4 &&
+        !strcmp(s, "\360\220\200\200..."));
+  assert(charset_wctomb(charset, s, 0x1fffff) == 4 &&
+        !strcmp(s, "\367\277\277\277..."));
+  assert(charset_wctomb(charset, s, 0x200000) == 5 &&
+        !strcmp(s, "\370\210\200\200\200.."));
+  assert(charset_wctomb(charset, s, 0x3ffffff) == 5 &&
+        !strcmp(s, "\373\277\277\277\277.."));
+  assert(charset_wctomb(charset, s, 0x4000000) == 6 &&
+        !strcmp(s, "\374\204\200\200\200\200."));
+  assert(charset_wctomb(charset, s, 0x7fffffff) == 6 &&
+        !strcmp(s, "\375\277\277\277\277\277."));
+}
+
+void test_ascii()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("us-ascii");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\177", 2) == 1 && wc == 127);
+  assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+
+  /* Encoder */
+  strcpy(s, "..");
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == -1);
+  assert(charset_wctomb(charset, s, 128) == -1);
+  assert(charset_wctomb(charset, s, 127) == 1 && !strcmp(s, "\177."));
+}
+
+void test_iso1()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("iso-8859-1");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+
+  /* Encoder */
+  strcpy(s, "..");
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == 1 && !strcmp(s, "\377."));
+  assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_iso2()
+{
+  struct charset *charset;
+  int wc;
+  char s[3];
+
+  charset = charset_find("iso-8859-2");
+  test_any(charset);
+
+  /* Decoder */
+  wc = 0;
+  assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+  assert(charset_mbtowc(charset, &wc, "\377", 2) == 1 && wc == 0x2d9);
+
+  /* Encoder */
+  strcpy(s, "..");
+  assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 255) == -1 && !strcmp(s, ".."));
+  assert(charset_wctomb(charset, s, 258) == 1 && !strcmp(s, "\303."));
+  assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_convert()
+{
+  const char *p;
+  char *q, *r;
+  char s[256];
+  size_t n, n2;
+  int i;
+
+  p = "\000x\302\200\375\277\277\277\277\277";
+  assert(charset_convert("UTF-8", "UTF-8", p, 10, &q, &n) == 0 &&
+        n == 10 && !strcmp(p, q));
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, &n) == 2 &&
+        n == 4 && !strcmp(q, "x##y"));
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, 0, &n) == 2 &&
+        n == 4);
+  assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, 0) == 2 &&
+        !strcmp(q, "x##y"));
+  assert(charset_convert("UTF-8", "iso-8859-1",
+                        "\302\200\304\200x", 5, &q, &n) == 1 &&
+        n == 3 && !strcmp(q, "\200?x"));
+  assert(charset_convert("iso-8859-1", "UTF-8", 
+                        "\000\200\377", 3, &q, &n) == 0 &&
+        n == 5 && !memcmp(q, "\000\302\200\303\277", 5));
+  assert(charset_convert("iso-8859-1", "iso-8859-1",
+                        "\000\200\377", 3, &q, &n) == 0 &&
+        n == 3 && !memcmp(q, "\000\200\377", 3));
+
+  assert(charset_convert("iso-8859-2", "utf-8", "\300", 1, &q, &n) == 0 &&
+        n == 2 && !strcmp(q, "\305\224"));
+  assert(charset_convert("utf-8", "iso-8859-2", "\305\224", 2, &q, &n) == 0 &&
+        n == 1 && !strcmp(q, "\300"));
+
+  for (i = 0; i < 256; i++)
+    s[i] = i;
+
+  assert(charset_convert("iso-8859-2", "utf-8", s, 256, &q, &n) == 0);
+  assert(charset_convert("utf-8", "iso-8859-2", q, n, &r, &n2) == 0);
+  assert(n2 == 256 && !memcmp(r, s, n2));
+}
+
+int main()
+{
+  test_utf8();
+  test_ascii();
+  test_iso1();
+  test_iso2();
+
+  test_convert();
+
+  return 0;
+}
diff --git a/src/share/utf8/charsetmap.h b/src/share/utf8/charsetmap.h
new file mode 100644 (file)
index 0000000..b812590
--- /dev/null
@@ -0,0 +1,79 @@
+/* This file was automatically generated by make_code_map.pl
+   please don't edit directly
+   Daniel Resare <noa@metamatrix.se>
+*/
+charset_map maps[] = {
+       {"ISO-8859-1",
+        {
+         0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+         0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+         0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+         0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+         0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+         0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+         0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+         0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+         0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+         0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+         0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+         0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+         0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+         0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+         0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+         0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+         0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+         0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
+         0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+         0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
+         0x00A0,0x00A1,0x00A2,0x00A3,0x00A4,0x00A5,0x00A6,0x00A7,
+         0x00A8,0x00A9,0x00AA,0x00AB,0x00AC,0x00AD,0x00AE,0x00AF,
+         0x00B0,0x00B1,0x00B2,0x00B3,0x00B4,0x00B5,0x00B6,0x00B7,
+         0x00B8,0x00B9,0x00BA,0x00BB,0x00BC,0x00BD,0x00BE,0x00BF,
+         0x00C0,0x00C1,0x00C2,0x00C3,0x00C4,0x00C5,0x00C6,0x00C7,
+         0x00C8,0x00C9,0x00CA,0x00CB,0x00CC,0x00CD,0x00CE,0x00CF,
+         0x00D0,0x00D1,0x00D2,0x00D3,0x00D4,0x00D5,0x00D6,0x00D7,
+         0x00D8,0x00D9,0x00DA,0x00DB,0x00DC,0x00DD,0x00DE,0x00DF,
+         0x00E0,0x00E1,0x00E2,0x00E3,0x00E4,0x00E5,0x00E6,0x00E7,
+         0x00E8,0x00E9,0x00EA,0x00EB,0x00EC,0x00ED,0x00EE,0x00EF,
+         0x00F0,0x00F1,0x00F2,0x00F3,0x00F4,0x00F5,0x00F6,0x00F7,
+         0x00F8,0x00F9,0x00FA,0x00FB,0x00FC,0x00FD,0x00FE,0x00FF
+        }
+       },
+       {"ISO-8859-2",
+        {
+         0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+         0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+         0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+         0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+         0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+         0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+         0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+         0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+         0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+         0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+         0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+         0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+         0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+         0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+         0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+         0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+         0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+         0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
+         0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+         0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
+         0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7,
+         0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B,
+         0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7,
+         0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C,
+         0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7,
+         0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E,
+         0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7,
+         0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF,
+         0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7,
+         0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F,
+         0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7,
+         0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9
+        }
+       },
+       {NULL}
+};
diff --git a/src/share/utf8/iconvert.c b/src/share/utf8/iconvert.c
new file mode 100644 (file)
index 0000000..f0311ee
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_ICONV
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iconvert.h"
+#include "share/alloc.h"
+
+/*
+ * Convert data from one encoding to another. Return:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : data was converted inexactly
+ *   2 : data was invalid (but still converted)
+ *
+ * We convert in two steps, via UTF-8, as this is the only
+ * reliable way of distinguishing between invalid input
+ * and valid input which iconv refuses to transliterate.
+ * We convert from UTF-8 twice, because we have no way of
+ * knowing whether the conversion was exact if iconv returns
+ * E2BIG (due to a bug in the specification of iconv).
+ * An alternative approach is to assume that the output of
+ * iconv is never more than 4 times as long as the input,
+ * but I prefer to avoid that assumption if possible.
+ */
+
+int iconvert(const char *fromcode, const char *tocode,
+            const char *from, size_t fromlen,
+            char **to, size_t *tolen)
+{
+  int ret = 0;
+  iconv_t cd1, cd2;
+  char *ib;
+  char *ob;
+  char *utfbuf = 0, *outbuf, *newbuf;
+  size_t utflen, outlen, ibl, obl, k;
+  char tbuf[2048];
+
+  cd1 = iconv_open("UTF-8", fromcode);
+  if (cd1 == (iconv_t)(-1))
+    return -1;
+
+  cd2 = (iconv_t)(-1);
+  /* Don't use strcasecmp() as it's locale-dependent. */
+  if (!strchr("Uu", tocode[0]) ||
+      !strchr("Tt", tocode[1]) ||
+      !strchr("Ff", tocode[2]) ||
+      tocode[3] != '-' ||
+      tocode[4] != '8' ||
+      tocode[5] != '\0') {
+    char *tocode1;
+
+    /*
+     * Try using this non-standard feature of glibc and libiconv.
+     * This is deliberately not a config option as people often
+     * change their iconv library without rebuilding applications.
+     */
+    tocode1 = (char *)safe_malloc_add_2op_(strlen(tocode), /*+*/11);
+    if (!tocode1)
+      goto fail;
+
+    strcpy(tocode1, tocode);
+    strcat(tocode1, "//TRANSLIT");
+    cd2 = iconv_open(tocode1, "UTF-8");
+    free(tocode1);
+
+    if (cd2 == (iconv_t)(-1))
+      cd2 = iconv_open(tocode, fromcode);
+
+    if (cd2 == (iconv_t)(-1)) {
+      iconv_close(cd1);
+      return -1;
+    }
+  }
+
+  utflen = 1; /*fromlen * 2 + 1; XXX */
+  utfbuf = (char *)malloc(utflen);
+  if (!utfbuf)
+    goto fail;
+
+  /* Convert to UTF-8 */
+  ib = (char *)from;
+  ibl = fromlen;
+  ob = utfbuf;
+  obl = utflen;
+  for (;;) {
+    k = iconv(cd1, &ib, &ibl, &ob, &obl);
+    assert((!k && !ibl) ||
+          (k == (size_t)(-1) && errno == E2BIG && ibl && obl < 6) ||
+          (k == (size_t)(-1) &&
+           (errno == EILSEQ || errno == EINVAL) && ibl));
+    if (!ibl)
+      break;
+    if (obl < 6) {
+      /* Enlarge the buffer */
+      if(utflen*2 < utflen) /* overflow check */
+       goto fail;
+      utflen *= 2;
+      newbuf = (char *)realloc(utfbuf, utflen);
+      if (!newbuf)
+       goto fail;
+      ob = (ob - utfbuf) + newbuf;
+      obl = utflen - (ob - newbuf);
+      utfbuf = newbuf;
+    }
+    else {
+      /* Invalid input */
+      ib++, ibl--;
+      *ob++ = '#', obl--;
+      ret = 2;
+      iconv(cd1, 0, 0, 0, 0);
+    }
+  }
+
+  if (cd2 == (iconv_t)(-1)) {
+    /* The target encoding was UTF-8 */
+    if (tolen)
+      *tolen = ob - utfbuf;
+    if (!to) {
+      free(utfbuf);
+      iconv_close(cd1);
+      return ret;
+    }
+    newbuf = (char *)safe_realloc_add_2op_(utfbuf, (ob - utfbuf), /*+*/1);
+    if (!newbuf)
+      goto fail;
+    ob = (ob - utfbuf) + newbuf;
+    *ob = '\0';
+    *to = newbuf;
+    iconv_close(cd1);
+    return ret;
+  }
+
+  /* Truncate the buffer to be tidy */
+  utflen = ob - utfbuf;
+  newbuf = (char *)realloc(utfbuf, utflen);
+  if (!newbuf)
+    goto fail;
+  utfbuf = newbuf;
+
+  /* Convert from UTF-8 to discover how long the output is */
+  outlen = 0;
+  ib = utfbuf;
+  ibl = utflen;
+  while (ibl) {
+    ob = tbuf;
+    obl = sizeof(tbuf);
+    k = iconv(cd2, &ib, &ibl, &ob, &obl);
+    assert((k != (size_t)(-1) && !ibl) ||
+          (k == (size_t)(-1) && errno == E2BIG && ibl) ||
+          (k == (size_t)(-1) && errno == EILSEQ && ibl));
+    if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+      /* Replace one character */
+      char *tb = "?";
+      size_t tbl = 1;
+
+      outlen += ob - tbuf;
+      ob = tbuf;
+      obl = sizeof(tbuf);
+      k = iconv(cd2, &tb, &tbl, &ob, &obl);
+      assert((!k && !tbl) ||
+            (k == (size_t)(-1) && errno == EILSEQ && tbl));
+      for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+       ;
+    }
+    outlen += ob - tbuf;
+  }
+  ob = tbuf;
+  obl = sizeof(tbuf);
+  k = iconv(cd2, 0, 0, &ob, &obl);
+  assert(!k);
+  outlen += ob - tbuf;
+
+  /* Convert from UTF-8 for real */
+  outbuf = (char *)safe_malloc_add_2op_(outlen, /*+*/1);
+  if (!outbuf)
+    goto fail;
+  ib = utfbuf;
+  ibl = utflen;
+  ob = outbuf;
+  obl = outlen;
+  while (ibl) {
+    k = iconv(cd2, &ib, &ibl, &ob, &obl);
+    assert((k != (size_t)(-1) && !ibl) ||
+          (k == (size_t)(-1) && errno == EILSEQ && ibl));
+    if (k && !ret)
+      ret = 1;
+    if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+      /* Replace one character */
+      char *tb = "?";
+      size_t tbl = 1;
+
+      k = iconv(cd2, &tb, &tbl, &ob, &obl);
+      assert((!k && !tbl) ||
+            (k == (size_t)(-1) && errno == EILSEQ && tbl));
+      for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+       ;
+    }
+  }
+  k = iconv(cd2, 0, 0, &ob, &obl);
+  assert(!k);
+  assert(!obl);
+  *ob = '\0';
+
+  free(utfbuf);
+  iconv_close(cd1);
+  iconv_close(cd2);
+  if (tolen)
+    *tolen = outlen;
+  if (!to) {
+    free(outbuf);
+    return ret;
+  }
+  *to = outbuf;
+  return ret;
+
+ fail:
+  if(0 != utfbuf)
+    free(utfbuf);
+  iconv_close(cd1);
+  if (cd2 != (iconv_t)(-1))
+    iconv_close(cd2);
+  return -2;
+}
+
+#endif /* HAVE_ICONV */
diff --git a/src/share/utf8/iconvert.h b/src/share/utf8/iconvert.h
new file mode 100644 (file)
index 0000000..1a1a06a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_ICONV
+
+/*
+ * Convert data from one encoding to another. Return:
+ *
+ *  -2 : memory allocation failed
+ *  -1 : unknown encoding
+ *   0 : data was converted exactly
+ *   1 : data was converted inexactly
+ *   2 : data was invalid (but still converted)
+ *
+ * We convert in two steps, via UTF-8, as this is the only
+ * reliable way of distinguishing between invalid input
+ * and valid input which iconv refuses to transliterate.
+ * We convert from UTF-8 twice, because we have no way of
+ * knowing whether the conversion was exact if iconv returns
+ * E2BIG (due to a bug in the specification of iconv).
+ * An alternative approach is to assume that the output of
+ * iconv is never more than 4 times as long as the input,
+ * but I prefer to avoid that assumption if possible.
+ */
+
+int iconvert(const char *fromcode, const char *tocode,
+            const char *from, size_t fromlen,
+            char **to, size_t *tolen) ;
+
+#endif /* HAVE_ICONV */
diff --git a/src/share/utf8/makemap.c b/src/share/utf8/makemap.c
new file mode 100644 (file)
index 0000000..72a9de1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ * 
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+  iconv_t cd;
+  const char *ib;
+  char *ob;
+  size_t ibl, obl, k;
+  unsigned char c, buf[4];
+  int i, wc;
+
+  if (argc != 2) {
+    printf("Usage: %s ENCODING\n", argv[0]);
+    printf("Output a charset map for the 8-bit ENCODING.\n");
+    return 1;
+  }
+
+  cd = iconv_open("UCS-4", argv[1]);
+  if (cd == (iconv_t)(-1)) {
+    perror("iconv_open");
+    return 1;
+  }
+
+  for (i = 0; i < 256; i++) {
+    c = i;
+    ib = &c;
+    ibl = 1;
+    ob = buf;
+    obl = 4;
+    k = iconv(cd, &ib, &ibl, &ob, &obl);
+    if (!k && !ibl && !obl) {
+      wc = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+      if (wc >= 0xffff) {
+       printf("Dodgy value.\n");
+       return 1;
+      }
+    }
+    else if (k == (size_t)(-1) && errno == EILSEQ)
+      wc = 0xffff;
+    else {
+      printf("Non-standard iconv.\n");
+      return 1;
+    }
+
+    if (i % 8 == 0)
+      printf("  ");
+    printf("0x%04x", wc);
+    if (i == 255)
+      printf("\n");
+    else if (i % 8 == 7)
+      printf(",\n");
+    else
+      printf(", ");
+  }
+
+  return 0;
+}
diff --git a/src/share/utf8/utf8.c b/src/share/utf8/utf8.c
new file mode 100644 (file)
index 0000000..303fe23
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * Buffer overflow checking added: Josh Coalson, 9/9/2007
+ *
+ * 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
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "share/alloc.h"
+#include "utf8.h"
+#include "charset.h"
+
+
+#ifdef _WIN32
+
+       /* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+        * code.
+        */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+    size_t size = 0, n;
+    int index = 0, out_index = 0;
+    unsigned char *out;
+    unsigned short c;
+
+    /* first calculate the size of the target string */
+    c = unicode[index++];
+    while(c) {
+        if(c < 0x0080) {
+            n = 1;
+        } else if(c < 0x0800) {
+            n = 2;
+        } else {
+            n = 3;
+        }
+        if(size+n < size) /* overflow check */
+            return NULL;
+        size += n;
+        c = unicode[index++];
+    }
+
+    out = safe_malloc_add_2op_(size, /*+*/1);
+    if (out == NULL)
+        return NULL;
+    index = 0;
+
+    c = unicode[index++];
+    while(c)
+    {
+        if(c < 0x080) {
+            out[out_index++] = (unsigned char)c;
+        } else if(c < 0x800) {
+            out[out_index++] = 0xc0 | (c >> 6);
+            out[out_index++] = 0x80 | (c & 0x3f);
+        } else {
+            out[out_index++] = 0xe0 | (c >> 12);
+            out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+            out[out_index++] = 0x80 | (c & 0x3f);
+        }
+        c = unicode[index++];
+    }
+    out[out_index] = 0x00;
+
+    return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+    size_t size = 0;
+    int index = 0, out_index = 0;
+    wchar_t *out;
+    unsigned char c;
+
+    /* first calculate the size of the target string */
+    c = utf8[index++];
+    while(c) {
+        if((c & 0x80) == 0) {
+            index += 0;
+        } else if((c & 0xe0) == 0xe0) {
+            index += 2;
+        } else {
+            index += 1;
+        }
+        if(size + 1 == 0) /* overflow check */
+            return NULL;
+        size++;
+        c = utf8[index++];
+    }
+
+    if(size + 1 == 0) /* overflow check */
+        return NULL;
+    out = safe_malloc_mul_2op_(size+1, /*times*/sizeof(wchar_t));
+    if (out == NULL)
+        return NULL;
+    index = 0;
+
+    c = utf8[index++];
+    while(c)
+    {
+        if((c & 0x80) == 0) {
+            out[out_index++] = c;
+        } else if((c & 0xe0) == 0xe0) {
+            out[out_index] = (c & 0x1F) << 12;
+               c = utf8[index++];
+            out[out_index] |= (c & 0x3F) << 6;
+               c = utf8[index++];
+            out[out_index++] |= (c & 0x3F);
+        } else {
+            out[out_index] = (c & 0x3F) << 6;
+               c = utf8[index++];
+            out[out_index++] |= (c & 0x3F);
+        }
+        c = utf8[index++];
+    }
+    out[out_index] = 0;
+
+    return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+       wchar_t *unicode;
+       int wchars, err;
+
+       wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+                       strlen(from), NULL, 0);
+
+       if(wchars == 0)
+       {
+               fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       if(wchars < 0) /* underflow check */
+               return -1;
+
+       unicode = safe_calloc_((size_t)wchars + 1, sizeof(unsigned short));
+       if(unicode == NULL) 
+       {
+               fprintf(stderr, "Out of memory processing string to UTF8\n");
+               return -1;
+       }
+
+       err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, 
+                       strlen(from), unicode, wchars);
+       if(err != wchars)
+       {
+               free(unicode);
+               fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       /* On NT-based windows systems, we could use WideCharToMultiByte(), but 
+        * MS doesn't actually have a consistent API across win32.
+        */
+       *to = make_utf8_string(unicode);
+
+       free(unicode);
+       return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+    wchar_t *unicode;
+    int chars, err;
+
+    /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but 
+     * MS doesn't actually have a consistent API across win32.
+     */
+    unicode = make_unicode_string(from);
+    if(unicode == NULL) 
+    {
+        fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+        return -1;
+    }
+
+    chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode,
+            -1, NULL, 0, NULL, NULL);
+
+    if(chars < 0) /* underflow check */
+        return -1;
+
+    if(chars == 0)
+    {
+        fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+        free(unicode);
+        return -1;
+    }
+
+    *to = safe_calloc_((size_t)chars + 1, sizeof(unsigned char));
+    if(*to == NULL) 
+    {
+        fprintf(stderr, "Out of memory processing string to local charset\n");
+        free(unicode);
+        return -1;
+    }
+
+    err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, 
+            -1, *to, chars, NULL, NULL);
+    if(err != chars)
+    {
+        fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+        free(unicode);
+        free(*to);
+        *to = NULL;
+        return -1;
+    }
+
+    free(unicode);
+    return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "iconvert.h"
+
+static const char *current_charset(void)
+{
+  const char *c = 0;
+#ifdef HAVE_LANGINFO_CODESET
+  c = nl_langinfo(CODESET);
+#endif
+
+  if (!c)
+    c = getenv("CHARSET");
+
+  return c? c : "US-ASCII";
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+                         const char *from, size_t fromlen,
+                         char **to, size_t *tolen)
+{
+  int ret = -1;
+
+#ifdef HAVE_ICONV
+  ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+  if (ret != -1)
+    return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+  ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+  if (ret != -1)
+    return ret;
+#endif
+
+  return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+                         const char *from, char **to, char replace)
+{
+  int ret;
+  size_t fromlen;
+  char *s;
+
+  fromlen = strlen(from);
+  ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+  if (ret == -2)
+    return -1;
+  if (ret != -1)
+    return ret;
+
+  s = safe_malloc_add_2op_(fromlen, /*+*/1);
+  if (!s)
+    return -1;
+  strcpy(s, from);
+  *to = s;
+  for (; *s; s++)
+    if (*s & ~0x7f)
+      *s = replace;
+  return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+  return convert_string(current_charset(), "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+  return convert_string("UTF-8", current_charset(), from, to, '?');
+}
+
+#endif
diff --git a/src/share/utf8/utf8_static.dsp b/src/share/utf8/utf8_static.dsp
new file mode 100644 (file)
index 0000000..199bfad
--- /dev/null
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="utf8_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=utf8_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "utf8_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "utf8_static.mak" CFG="utf8_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "utf8_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "utf8_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "utf8"\r
+# PROP Scc_LocalPath "..\..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "utf8_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I ".\include" /I "..\..\..\include" /I "..\..\..\include\share" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "utf8_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\..\include" /I "..\..\..\include\share" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "utf8_static - Win32 Release"\r
+# Name "utf8_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\charset.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iconvert.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utf8.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Private Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Protected Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\share\utf8.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/share/utf8/utf8_static.vcproj b/src/share/utf8/utf8_static.vcproj
new file mode 100644 (file)
index 0000000..415254f
--- /dev/null
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="utf8_static"\r
+       ProjectGUID="{4cefbc92-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="utf8_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\..\include;..\..\..\include\share"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\charmaps.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\charset.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\charsetmap.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Public Header Files"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\include\share\utf8.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\charset.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\iconvert.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\utf8.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_grabbag/Makefile.am b/src/test_grabbag/Makefile.am
new file mode 100644 (file)
index 0000000..825d1cb
--- /dev/null
@@ -0,0 +1,21 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+SUBDIRS = cuesheet picture
+
+EXTRA_DIST = \
+       Makefile.lite
diff --git a/src/test_grabbag/Makefile.lite b/src/test_grabbag/Makefile.lite
new file mode 100644 (file)
index 0000000..93512c3
--- /dev/null
@@ -0,0 +1,40 @@
+#  test_grabbag - Simple testers for the grabbag library
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+
+.PHONY: cuesheet picture
+all: cuesheet picture
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+debug   : CONFIG = debug
+valgrind: CONFIG = valgrind
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+cuesheet:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+picture:
+       (cd $@ ; $(MAKE) -f Makefile.lite $(CONFIG))
+
+clean:
+       -(cd cuesheet ; $(MAKE) -f Makefile.lite clean)
+       -(cd picture ; $(MAKE) -f Makefile.lite clean)
diff --git a/src/test_grabbag/cuesheet/Makefile.am b/src/test_grabbag/cuesheet/Makefile.am
new file mode 100644 (file)
index 0000000..1d6d709
--- /dev/null
@@ -0,0 +1,31 @@
+#  test_cuesheet - Simple tester for cuesheet routines in grabbag
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_cuesheet.dsp \
+       test_cuesheet.vcproj
+
+noinst_PROGRAMS = test_cuesheet
+test_cuesheet_SOURCES = \
+       main.c
+test_cuesheet_LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       -lm
diff --git a/src/test_grabbag/cuesheet/Makefile.lite b/src/test_grabbag/cuesheet/Makefile.lite
new file mode 100644 (file)
index 0000000..0178b1e
--- /dev/null
@@ -0,0 +1,40 @@
+#  test_cuesheet - Simple tester for cuesheet routines in grabbag
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_cuesheet
+
+INCLUDES = -I./include -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lgrabbag -lreplaygain_analysis -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_grabbag/cuesheet/main.c b/src/test_grabbag/cuesheet/main.c
new file mode 100644 (file)
index 0000000..bb99834
--- /dev/null
@@ -0,0 +1,138 @@
+/* test_cuesheet - Simple tester for cuesheet routines in grabbag
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+static int do_cuesheet(const char *infilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+       FILE *fin, *fout;
+       const char *error_message;
+       char tmpfilename[4096];
+       unsigned last_line_read;
+       FLAC__StreamMetadata *cuesheet;
+
+       FLAC__ASSERT(strlen(infilename) + 2 < sizeof(tmpfilename));
+
+       /*
+        * pass 1
+        */
+       if(0 == strcmp(infilename, "-")) {
+               fin = stdin;
+       }
+       else if(0 == (fin = fopen(infilename, "r"))) {
+               fprintf(stderr, "can't open file %s for reading: %s\n", infilename, strerror(errno));
+               return 255;
+       }
+       if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, is_cdda, lead_out_offset))) {
+               if(fin != stdin)
+                       fclose(fin);
+       }
+       else {
+               printf("pass1: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+               if(fin != stdin)
+                       fclose(fin);
+               return 1;
+       }
+       if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+               printf("pass1: illegal cuesheet: \"%s\"\n", error_message);
+               FLAC__metadata_object_delete(cuesheet);
+               return 1;
+       }
+       sprintf(tmpfilename, "%s.1", infilename);
+       if(0 == (fout = fopen(tmpfilename, "w"))) {
+               fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+               FLAC__metadata_object_delete(cuesheet);
+               return 255;
+       }
+       grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+       FLAC__metadata_object_delete(cuesheet);
+       fclose(fout);
+
+       /*
+        * pass 2
+        */
+       if(0 == (fin = fopen(tmpfilename, "r"))) {
+               fprintf(stderr, "can't open file %s for reading: %s\n", tmpfilename, strerror(errno));
+               return 255;
+       }
+       if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, is_cdda, lead_out_offset))) {
+               if(fin != stdin)
+                       fclose(fin);
+       }
+       else {
+               printf("pass2: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+               if(fin != stdin)
+                       fclose(fin);
+               return 1;
+       }
+       if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+               printf("pass2: illegal cuesheet: \"%s\"\n", error_message);
+               FLAC__metadata_object_delete(cuesheet);
+               return 1;
+       }
+       sprintf(tmpfilename, "%s.2", infilename);
+       if(0 == (fout = fopen(tmpfilename, "w"))) {
+               fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+               FLAC__metadata_object_delete(cuesheet);
+               return 255;
+       }
+       grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+       FLAC__metadata_object_delete(cuesheet);
+       fclose(fout);
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       FLAC__uint64 lead_out_offset;
+       FLAC__bool is_cdda = false;
+       const char *usage = "usage: test_cuesheet cuesheet_file lead_out_offset [ cdda ]\n";
+
+       if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+               printf(usage);
+               return 0;
+       }
+
+       if(argc < 3 || argc > 4) {
+               fprintf(stderr, usage);
+               return 255;
+       }
+
+       lead_out_offset = (FLAC__uint64)strtoul(argv[2], 0, 10);
+       if(argc == 4) {
+               if(0 == strcmp(argv[3], "cdda"))
+                       is_cdda = true;
+               else {
+                       fprintf(stderr, usage);
+                       return 255;
+               }
+       }
+
+       return do_cuesheet(argv[1], is_cdda, lead_out_offset);
+}
diff --git a/src/test_grabbag/cuesheet/test_cuesheet.dsp b/src/test_grabbag/cuesheet/test_cuesheet.dsp
new file mode 100644 (file)
index 0000000..778822d
--- /dev/null
@@ -0,0 +1,96 @@
+# Microsoft Developer Studio Project File - Name="test_cuesheet" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_cuesheet - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_cuesheet.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_cuesheet.mak" CFG="test_cuesheet - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_cuesheet - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_cuesheet - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_cuesheet - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\obj\release\lib\grabbag_static.lib ..\..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\..\obj\release\lib\libFLAC_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_cuesheet - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\obj\debug\lib\grabbag_static.lib ..\..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\..\obj\debug\lib\libFLAC_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_cuesheet - Win32 Release"\r
+# Name "test_cuesheet - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_grabbag/cuesheet/test_cuesheet.vcproj b/src/test_grabbag/cuesheet/test_cuesheet.vcproj
new file mode 100644 (file)
index 0000000..21d2c25
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_cuesheet"\r
+       ProjectGUID="{4cefbc8b-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_cuesheet"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_grabbag/picture/Makefile.am b/src/test_grabbag/picture/Makefile.am
new file mode 100644 (file)
index 0000000..1f5d655
--- /dev/null
@@ -0,0 +1,30 @@
+#  test_picture - Simple tester for picture routines in grabbag
+#  Copyright (C) 2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_picture.dsp \
+       test_picture.vcproj
+
+noinst_PROGRAMS = test_picture
+test_picture_SOURCES = \
+       main.c
+test_picture_LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       -lm
diff --git a/src/test_grabbag/picture/Makefile.lite b/src/test_grabbag/picture/Makefile.lite
new file mode 100644 (file)
index 0000000..af7ab5f
--- /dev/null
@@ -0,0 +1,40 @@
+#  test_picture - Simple tester for picture routines in grabbag
+#  Copyright (C) 2006,2007  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
+#
+
+topdir = ../../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_picture
+
+INCLUDES = -I./include -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lgrabbag -lreplaygain_analysis -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_grabbag/picture/main.c b/src/test_grabbag/picture/main.c
new file mode 100644 (file)
index 0000000..2ca34a6
--- /dev/null
@@ -0,0 +1,224 @@
+/* test_picture - Simple tester for picture routines in grabbag
+ * Copyright (C) 2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+
+typedef struct {
+       const char *path;
+       const char *mime_type;
+       const char *description;
+       FLAC__uint32 width;
+       FLAC__uint32 height;
+       FLAC__uint32 depth;
+       FLAC__uint32 colors;
+       FLAC__StreamMetadata_Picture_Type type;
+} PictureFile;
+
+PictureFile picturefiles[] = {
+       { "0.gif", "image/gif" , "", 24, 24, 24, 2, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "1.gif", "image/gif" , "", 12,  8, 24, 256, FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER },
+       { "2.gif", "image/gif" , "", 16, 14, 24, 128, FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER },
+       { "0.jpg", "image/jpeg", "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "4.jpg", "image/jpeg", "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "0.png", "image/png" , "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "1.png", "image/png" , "", 30, 20,  8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "2.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "3.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "4.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "5.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "6.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "7.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+       { "8.png", "image/png" , "", 32, 32, 32, 0, 999 }
+};
+
+static FLAC__bool debug_ = false;
+
+static FLAC__bool failed_(const char *msg)
+{
+    if(msg)
+        printf("FAILED, %s\n", msg);
+    else
+        printf("FAILED\n");
+
+    return false;
+}
+
+static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, const char *res, FLAC__bool fn_only)
+{
+       FLAC__StreamMetadata *obj;
+       const char *error;
+       char s[4096];
+       if(fn_only)
+#if defined _MSC_VER || defined __MINGW32__
+               _snprintf(s, sizeof(s)-1, "%s/%s", prefix, pf->path);
+#else
+               snprintf(s, sizeof(s)-1, "%s/%s", prefix, pf->path);
+#endif
+       else
+#if defined _MSC_VER || defined __MINGW32__
+               _snprintf(s, sizeof(s)-1, "%u|%s|%s|%s|%s/%s", (unsigned)pf->type, pf->mime_type, pf->description, res, prefix, pf->path);
+#else
+               snprintf(s, sizeof(s)-1, "%u|%s|%s|%s|%s/%s", (unsigned)pf->type, pf->mime_type, pf->description, res, prefix, pf->path);
+#endif
+
+       printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
+       if(0 == (obj = grabbag__picture_parse_specification(s, &error)))
+               return failed_(error);
+       if(debug_) {
+               printf("\ntype=%u (%s)\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n",
+                       obj->data.picture.type,
+                       obj->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED?
+                               FLAC__StreamMetadata_Picture_TypeString[obj->data.picture.type] : "UNDEFINED",
+                       obj->data.picture.mime_type,
+                       obj->data.picture.description,
+                       obj->data.picture.width,
+                       obj->data.picture.height,
+                       obj->data.picture.depth,
+                       obj->data.picture.colors,
+                       obj->data.picture.data_length
+               );
+       }
+       if(obj->data.picture.type != (fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type))
+               return failed_("picture type mismatch");
+       if(strcmp(obj->data.picture.mime_type, pf->mime_type))
+               return failed_("picture MIME type mismatch");
+       if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description))
+               return failed_("picture description mismatch");
+       if(obj->data.picture.width != pf->width)
+               return failed_("picture width mismatch");
+       if(obj->data.picture.height != pf->height)
+               return failed_("picture height mismatch");
+       if(obj->data.picture.depth != pf->depth)
+               return failed_("picture depth mismatch");
+       if(obj->data.picture.colors != pf->colors)
+               return failed_("picture colors mismatch");
+       printf("OK\n");
+       FLAC__metadata_object_delete(obj);
+       return true;
+}
+
+static FLAC__bool do_picture(const char *prefix)
+{
+       FLAC__StreamMetadata *obj;
+       const char *error;
+       size_t i;
+
+    printf("\n+++ grabbag unit test: picture\n\n");
+
+       /* invalid spec: no filename */
+       printf("testing grabbag__picture_parse_specification(\"\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected, error: %s)\n", error);
+
+       /* invalid spec: no filename */
+       printf("testing grabbag__picture_parse_specification(\"||||\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("||||", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: no filename */
+       printf("testing grabbag__picture_parse_specification(\"|image/gif|||\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|image/gif|||", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: bad resolution */
+       printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320|0.gif\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320|0.gif", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: bad resolution */
+       printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240|0.gif\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: no filename */
+       printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9|\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9|", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: #colors exceeds color depth */
+       printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9/2345|0.gif\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: standard icon has to be 32x32 PNG */
+       printf("testing grabbag__picture_parse_specification(\"1|-->|desc|32x24x9|0.gif\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       /* invalid spec: need resolution for linked URL */
+       printf("testing grabbag__picture_parse_specification(\"|-->|desc||http://blah.blah.blah/z.gif\")... ");
+       if(0 != (obj = grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif", &error)))
+               return failed_("expected error, got object");
+       printf("OK (failed as expected: %s)\n", error);
+
+       printf("testing grabbag__picture_parse_specification(\"|-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... ");
+       if(0 == (obj = grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error)))
+               return failed_(error);
+       printf("OK\n");
+       FLAC__metadata_object_delete(obj);
+
+       /* test automatic parsing of picture files from only the file name */
+       for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+               if(!test_one_picture(prefix, picturefiles+i, "", /*fn_only=*/true))
+                       return false;
+
+       /* test automatic parsing of picture files to get resolution/color info */
+       for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+               if(!test_one_picture(prefix, picturefiles+i, "", /*fn_only=*/false))
+                       return false;
+
+       picturefiles[0].width = 320;
+       picturefiles[0].height = 240;
+       picturefiles[0].depth = 3;
+       picturefiles[0].colors = 2;
+       if(!test_one_picture(prefix, picturefiles+0, "320x240x3/2", /*fn_only=*/false))
+               return false;
+
+       return true;
+}
+
+int main(int argc, char *argv[])
+{
+       const char *usage = "usage: test_pictures path_prefix\n";
+
+       if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+               printf(usage);
+               return 0;
+       }
+
+       if(argc != 2) {
+               fprintf(stderr, usage);
+               return 255;
+       }
+
+       return do_picture(argv[1])? 0 : 1;
+}
diff --git a/src/test_grabbag/picture/test_picture.dsp b/src/test_grabbag/picture/test_picture.dsp
new file mode 100644 (file)
index 0000000..dd7879c
--- /dev/null
@@ -0,0 +1,96 @@
+# Microsoft Developer Studio Project File - Name="test_picture" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_picture - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_picture.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_picture.mak" CFG="test_picture - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_picture - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_picture - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_picture - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\..\obj\release\lib\grabbag_static.lib ..\..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\..\obj\release\lib\libFLAC_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_picture - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\..\obj\debug\lib\grabbag_static.lib ..\..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\..\obj\debug\lib\libFLAC_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_picture - Win32 Release"\r
+# Name "test_picture - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_grabbag/picture/test_picture.vcproj b/src/test_grabbag/picture/test_picture.vcproj
new file mode 100644 (file)
index 0000000..6fe1307
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_picture"\r
+       ProjectGUID="{4cefbc8f-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_picture"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_libFLAC++/Makefile.am b/src/test_libFLAC++/Makefile.am
new file mode 100644 (file)
index 0000000..462cbf2
--- /dev/null
@@ -0,0 +1,42 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_libFLAC++.dsp \
+       test_libFLAC++.vcproj
+
+noinst_PROGRAMS = test_libFLAC++
+test_libFLAC___LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/test_libs_common/libtest_libs_common.la \
+       $(top_builddir)/src/libFLAC++/libFLAC++.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+test_libFLAC___SOURCES = \
+       decoders.cpp \
+       encoders.cpp \
+       main.cpp \
+       metadata.cpp \
+       metadata_manip.cpp \
+       metadata_object.cpp \
+       decoders.h \
+       encoders.h \
+       metadata.h
diff --git a/src/test_libFLAC++/Makefile.lite b/src/test_libFLAC++/Makefile.lite
new file mode 100644 (file)
index 0000000..cf7eb4b
--- /dev/null
@@ -0,0 +1,47 @@
+#  test_libFLAC++ - Unit tester for libFLAC++
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_libFLAC++
+
+INCLUDES = -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libtest_libs_common.a $(libdir)/libFLAC++.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC++ -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_CPP = \
+       decoders.cpp \
+       encoders.cpp \
+       main.cpp \
+       metadata.cpp \
+       metadata_manip.cpp \
+       metadata_object.cpp
+
+include $(topdir)/build/exe.mk
+
+LINK = $(CCC) $(LINKAGE)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libFLAC++/decoders.cpp b/src/test_libFLAC++/decoders.cpp
new file mode 100644 (file)
index 0000000..fc78c0d
--- /dev/null
@@ -0,0 +1,1179 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h" // for ::FLAC__metadata_object_is_equal()
+#include "FLAC++/decoder.h"
+#include "share/grabbag.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+}
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+typedef enum {
+       LAYER_STREAM = 0, /* FLAC__stream_decoder_init_stream() without seeking */
+       LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_stream() with seeking */
+       LAYER_FILE, /* FLAC__stream_decoder_init_FILE() */
+       LAYER_FILENAME /* FLAC__stream_decoder_init_file() */
+} Layer;
+
+static const char * const LayerString[] = {
+       "Stream",
+       "Seekable Stream",
+       "FILE*",
+       "Filename"
+};
+
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static unsigned num_expected_;
+static off_t flacfilesize_;
+
+static const char *flacfilename(bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC::Decoder::Stream *decoder)
+{
+       FLAC::Decoder::Stream::State state = decoder->get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+
+       return false;
+}
+
+static void init_metadata_blocks_()
+{
+       mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_()
+{
+       mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static bool generate_file_(FLAC__bool is_ogg)
+{
+       printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &picture_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+       /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+       if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+               return die_("creating the encoded file");
+
+       return true;
+}
+
+
+class DecoderCommon {
+public:
+       Layer layer_;
+       unsigned current_metadata_number_;
+       bool ignore_errors_;
+       bool error_occurred_;
+
+       DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { }
+       ::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__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:
+       FILE *file_;
+
+       StreamDecoder(Layer layer): FLAC::Decoder::Stream(), DecoderCommon(layer), file_(0) { }
+       ~StreamDecoder() { }
+
+       // from FLAC::Decoder::Stream
+       ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+       ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+       ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+       ::FLAC__StreamDecoderLengthStatus 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 test_respond(bool is_ogg);
+};
+
+::FLAC__StreamDecoderReadStatus StreamDecoder::read_callback(FLAC__byte buffer[], size_t *bytes)
+{
+       const size_t requested_bytes = *bytes;
+
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+       if(feof(file_)) {
+               *bytes = 0;
+               return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+       }
+       else if(requested_bytes > 0) {
+               *bytes = ::fread(buffer, 1, requested_bytes, file_);
+               if(*bytes == 0) {
+                       if(feof(file_))
+                               return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+                       else
+                               return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+               }
+               else {
+                       return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+               }
+       }
+       else
+               return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+::FLAC__StreamDecoderSeekStatus StreamDecoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+       if(layer_ == LAYER_STREAM)
+               return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+       if(fseeko(file_, (off_t)absolute_byte_offset, SEEK_SET) < 0) {
+               error_occurred_ = true;
+               return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       return ::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+::FLAC__StreamDecoderTellStatus StreamDecoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+       if(layer_ == LAYER_STREAM)
+               return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+       off_t offset = ftello(file_);
+       *absolute_byte_offset = (FLAC__uint64)offset;
+
+       if(offset < 0) {
+               error_occurred_ = true;
+               return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       return ::FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+::FLAC__StreamDecoderLengthStatus StreamDecoder::length_callback(FLAC__uint64 *stream_length)
+{
+       if(layer_ == LAYER_STREAM)
+               return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+
+       if(error_occurred_)
+               return ::FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+       *stream_length = (FLAC__uint64)flacfilesize_;
+       return ::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+bool StreamDecoder::eof_callback()
+{
+       if(layer_ == LAYER_STREAM)
+               return false;
+
+       if(error_occurred_)
+               return true;
+
+       return (bool)feof(file_);
+}
+
+::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)
+{
+       common_metadata_callback_(metadata);
+}
+
+void StreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       common_error_callback_(status);
+}
+
+bool StreamDecoder::test_respond(bool is_ogg)
+{
+       ::FLAC__StreamDecoderInitStatus init_status;
+
+       if(!set_md5_checking(true)) {
+               printf("FAILED at set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       printf("testing init%s()... ", is_ogg? "_ogg":"");
+       init_status = is_ogg? init_ogg() : init();
+       if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, this);
+       printf("OK\n");
+
+       current_metadata_number_ = 0;
+
+       if(fseeko(file_, 0, SEEK_SET) < 0) {
+               printf("FAILED rewinding input, errno = %d\n", errno);
+               return false;
+       }
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!process_until_end_of_stream()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       if(!finish()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       return true;
+}
+
+class FileDecoder : public FLAC::Decoder::File, public DecoderCommon {
+public:
+       FileDecoder(Layer layer): FLAC::Decoder::File(), DecoderCommon(layer) { }
+       ~FileDecoder() { }
+
+       // from FLAC::Decoder::Stream
+       ::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 test_respond(bool is_ogg);
+};
+
+::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::test_respond(bool is_ogg)
+{
+       ::FLAC__StreamDecoderInitStatus init_status;
+
+       if(!set_md5_checking(true)) {
+               printf("FAILED at set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       switch(layer_) {
+               case LAYER_FILE:
+                       {
+                               printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+                               FILE *file = ::fopen(flacfilename(is_ogg), "rb");
+                               if(0 == file) {
+                                       printf("ERROR (%s)\n", strerror(errno));
+                                       return false;
+                               }
+                               printf("OK\n");
+
+                               printf("testing init%s()... ", is_ogg? "_ogg":"");
+                               init_status = is_ogg? init_ogg(file) : init(file);
+                       }
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg? init_ogg(flacfilename(is_ogg)) : init(flacfilename(is_ogg));
+                       break;
+               default:
+                       die_("internal error 001");
+                       return false;
+       }
+       if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, this);
+       printf("OK\n");
+
+       current_metadata_number_ = 0;
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!process_until_end_of_stream()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       if(!finish()) {
+               State state = get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       return true;
+}
+
+
+static FLAC::Decoder::Stream *new_by_layer(Layer layer)
+{
+       if(layer < LAYER_FILE)
+               return new StreamDecoder(layer);
+       else
+               return new FileDecoder(layer);
+}
+
+static bool test_stream_decoder(Layer layer, bool is_ogg)
+{
+       FLAC::Decoder::Stream *decoder;
+       ::FLAC__StreamDecoderInitStatus init_status;
+       bool expect;
+
+       printf("\n+++ libFLAC++ unit test: FLAC::Decoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+       //
+       // test new -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new_by_layer(layer);
+       if(0 == decoder) {
+               printf("FAILED, new returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing is_valid()... ");
+       if(!decoder->is_valid()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test new -> init -> delete
+       //
+       printf("allocating decoder instance... ");
+       decoder = new_by_layer(layer);
+       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%s()... ", is_ogg? "_ogg":"");
+       switch(layer) {
+               case LAYER_STREAM:
+               case LAYER_SEEKABLE_STREAM:
+                       dynamic_cast<StreamDecoder*>(decoder)->file_ = stdin;
+                       init_status = is_ogg? decoder->init_ogg() : decoder->init();
+                       break;
+               case LAYER_FILE:
+                       init_status = is_ogg?
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(stdin) :
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init(stdin);
+                       break;
+               case LAYER_FILENAME:
+                       init_status = is_ogg?
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
+                       break;
+               default:
+                       die_("internal error 006");
+                       return false;
+       }
+       if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, decoder);
+       printf("OK\n");
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       //
+       // test normal usage
+       //
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("allocating decoder instance... ");
+       decoder = new_by_layer(layer);
+       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");
+
+       if(is_ogg) {
+               printf("testing set_ogg_serial_number()... ");
+               if(!decoder->set_ogg_serial_number(file_utils__ogg_serial_number))
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+       }
+
+       if(!decoder->set_md5_checking(true)) {
+               printf("FAILED at set_md5_checking(), returned false\n");
+               return false;
+       }
+
+       switch(layer) {
+               case LAYER_STREAM:
+               case LAYER_SEEKABLE_STREAM:
+                       printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+                       dynamic_cast<StreamDecoder*>(decoder)->file_ = ::fopen(flacfilename(is_ogg), "rb");
+                       if(0 == dynamic_cast<StreamDecoder*>(decoder)->file_) {
+                               printf("ERROR (%s)\n", strerror(errno));
+                               return false;
+                       }
+                       printf("OK\n");
+
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg? decoder->init_ogg() : decoder->init();
+                       break;
+               case LAYER_FILE:
+                       {
+                               printf("opening FLAC file... ");
+                               FILE *file = ::fopen(flacfilename(is_ogg), "rb");
+                               if(0 == file) {
+                                       printf("ERROR (%s)\n", strerror(errno));
+                                       return false;
+                               }
+                               printf("OK\n");
+
+                               printf("testing init%s()... ", is_ogg? "_ogg":"");
+                               init_status = is_ogg?
+                                       dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(file) :
+                                       dynamic_cast<FLAC::Decoder::File*>(decoder)->init(file);
+                       }
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg?
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
+                               dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
+                       break;
+               default:
+                       die_("internal error 009");
+                       return false;
+       }
+       if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, decoder);
+       printf("OK\n");
+
+       printf("testing get_state()... ");
+       FLAC::Decoder::Stream::State state = decoder->get_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+
+       dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
+       dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = false;
+       dynamic_cast<DecoderCommon*>(decoder)->error_occurred_ = false;
+
+       printf("testing get_md5_checking()... ");
+       if(!decoder->get_md5_checking()) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing process_until_end_of_metadata()... ");
+       if(!decoder->process_until_end_of_metadata())
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing process_single()... ");
+       if(!decoder->process_single())
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing skip_single_frame()... ");
+       if(!decoder->skip_single_frame())
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILE) {
+               printf("testing flush()... ");
+               if(!decoder->flush())
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+
+               dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = true;
+               printf("testing process_single()... ");
+               if(!decoder->process_single())
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+               dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = false;
+       }
+
+       expect = (layer != LAYER_STREAM);
+       printf("testing seek_absolute()... ");
+       if(decoder->seek_absolute(0) != expect)
+               return die_s_(expect? "returned false" : "returned true", decoder);
+       printf("OK\n");
+
+       printf("testing process_until_end_of_stream()... ");
+       if(!decoder->process_until_end_of_stream())
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       expect = (layer != LAYER_STREAM);
+       printf("testing seek_absolute()... ");
+       if(decoder->seek_absolute(0) != expect)
+               return die_s_(expect? "returned false" : "returned true", decoder);
+       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 reasonable answer */
+               printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+               if(blocksize == 0)
+                       return false;
+       }
+
+       printf("testing get_channel_assignment()... ");
+       {
+               ::FLAC__ChannelAssignment ca = decoder->get_channel_assignment();
+               printf("returned %u (%s)... OK\n", (unsigned)ca, ::FLAC__ChannelAssignmentString[ca]);
+       }
+
+       if(layer < LAYER_FILE) {
+               printf("testing reset()... ");
+               if(!decoder->reset())
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+
+               if(layer == LAYER_STREAM) {
+                       /* after a reset() we have to rewind the input ourselves */
+                       printf("rewinding input... ");
+                       if(fseeko(dynamic_cast<StreamDecoder*>(decoder)->file_, 0, SEEK_SET) < 0) {
+                               printf("FAILED, errno = %d\n", errno);
+                               return false;
+                       }
+                       printf("OK\n");
+               }
+
+               dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
+
+               printf("testing process_until_end_of_stream()... ");
+               if(!decoder->process_until_end_of_stream())
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+       }
+
+       printf("testing finish()... ");
+       if(!decoder->finish()) {
+               FLAC::Decoder::Stream::State state = decoder->get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)state), state.as_cstring());
+               return false;
+       }
+       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;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing set_metadata_respond_all()... ");
+       if(!decoder->set_metadata_respond_all()) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_VORBIS_COMMENT)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &picture_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               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(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
+               return false;
+
+       if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+               ::fclose(dynamic_cast<StreamDecoder*>(decoder)->file_);
+
+       printf("freeing decoder instance... ");
+       delete decoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+bool test_decoders()
+{
+       FLAC__bool is_ogg = false;
+
+       while(1) {
+               init_metadata_blocks_();
+
+               if(!generate_file_(is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_FILE, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+                       return false;
+
+               (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+               free_metadata_blocks_();
+
+               if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+                       break;
+               is_ogg = true;
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC++/decoders.h b/src/test_libFLAC++/decoders.h
new file mode 100644 (file)
index 0000000..422c31c
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.cpp b/src/test_libFLAC++/encoders.cpp
new file mode 100644 (file)
index 0000000..6b1ab69
--- /dev/null
@@ -0,0 +1,553 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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"
+#include "FLAC/assert.h"
+#include "FLAC++/encoder.h"
+#include "share/grabbag.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+}
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef enum {
+       LAYER_STREAM = 0, /* FLAC__stream_encoder_init_stream() without seeking */
+       LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_stream() with seeking */
+       LAYER_FILE, /* FLAC__stream_encoder_init_FILE() */
+       LAYER_FILENAME /* FLAC__stream_encoder_init_file() */
+} Layer;
+
+static const char * const LayerString[] = {
+       "Stream",
+       "Seekable Stream",
+       "FILE*",
+       "Filename"
+};
+
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
+static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+
+static const char *flacfilename(bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static bool die_s_(const char *msg, const FLAC::Encoder::Stream *encoder)
+{
+       FLAC::Encoder::Stream::State state = encoder->get_state();
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
+       if(state == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+               FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+               printf("      verify decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+       }
+
+       return false;
+}
+
+static void init_metadata_blocks_()
+{
+       mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_()
+{
+       mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+class StreamEncoder : public FLAC::Encoder::Stream {
+public:
+       Layer layer_;
+       FILE *file_;
+
+       StreamEncoder(Layer layer): FLAC::Encoder::Stream(), layer_(layer), file_(0) { }
+       ~StreamEncoder() { }
+
+       // from FLAC::Encoder::Stream
+       ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
+       ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame);
+       ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
+       ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
+       void metadata_callback(const ::FLAC__StreamMetadata *metadata);
+};
+
+::FLAC__StreamEncoderReadStatus StreamEncoder::read_callback(FLAC__byte buffer[], size_t *bytes)
+{
+       if(*bytes > 0) {
+               *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file_);
+               if(ferror(file_))
+                       return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+               else if(*bytes == 0)
+                       return ::FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+               else
+                       return ::FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+       }
+       else
+               return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+}
+
+::FLAC__StreamEncoderWriteStatus StreamEncoder::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
+{
+       (void)samples, (void)current_frame;
+
+       if(fwrite(buffer, 1, bytes, file_) != bytes)
+               return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+       else
+               return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+::FLAC__StreamEncoderSeekStatus StreamEncoder::seek_callback(FLAC__uint64 absolute_byte_offset)
+{
+       if(layer_==LAYER_STREAM)
+               return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+       else if(fseek(file_, (long)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+::FLAC__StreamEncoderTellStatus StreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+       long pos;
+       if(layer_==LAYER_STREAM)
+               return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+       else if((pos = ftell(file_)) < 0)
+               return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+       else {
+               *absolute_byte_offset = (FLAC__uint64)pos;
+               return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+       }
+}
+
+void StreamEncoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+       (void)metadata;
+}
+
+class FileEncoder : public FLAC::Encoder::File {
+public:
+       Layer layer_;
+
+       FileEncoder(Layer layer): FLAC::Encoder::File(), layer_(layer) { }
+       ~FileEncoder() { }
+
+       // from FLAC::Encoder::File
+       void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
+};
+
+void FileEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
+{
+       (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
+}
+
+static FLAC::Encoder::Stream *new_by_layer(Layer layer)
+{
+       if(layer < LAYER_FILE)
+               return new StreamEncoder(layer);
+       else
+               return new FileEncoder(layer);
+}
+
+static bool test_stream_encoder(Layer layer, bool is_ogg)
+{
+       FLAC::Encoder::Stream *encoder;
+       ::FLAC__StreamEncoderInitStatus init_status;
+       FILE *file = 0;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1] = { samples };
+       unsigned i;
+
+       printf("\n+++ libFLAC++ unit test: FLAC::Encoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
+
+       printf("allocating encoder instance... ");
+       encoder = new_by_layer(layer);
+       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");
+
+       if(is_ogg) {
+               printf("testing set_ogg_serial_number()... ");
+               if(!encoder->set_ogg_serial_number(file_utils__ogg_serial_number))
+                       return die_s_("returned false", encoder);
+               printf("OK\n");
+       }
+
+       printf("testing set_verify()... ");
+       if(!encoder->set_verify(true))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_streamable_subset()... ");
+       if(!encoder->set_streamable_subset(true))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_channels()... ");
+       if(!encoder->set_channels(streaminfo_.data.stream_info.channels))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_bits_per_sample()... ");
+       if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_sample_rate()... ");
+       if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_compression_level()... ");
+       if(!encoder->set_compression_level((unsigned)(-1)))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_blocksize()... ");
+       if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_do_mid_side_stereo()... ");
+       if(!encoder->set_do_mid_side_stereo(false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_loose_mid_side_stereo()... ");
+       if(!encoder->set_loose_mid_side_stereo(false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_max_lpc_order()... ");
+       if(!encoder->set_max_lpc_order(0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_qlp_coeff_precision()... ");
+       if(!encoder->set_qlp_coeff_precision(0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_do_qlp_coeff_prec_search()... ");
+       if(!encoder->set_do_qlp_coeff_prec_search(false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_do_escape_coding()... ");
+       if(!encoder->set_do_escape_coding(false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_do_exhaustive_model_search()... ");
+       if(!encoder->set_do_exhaustive_model_search(false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_min_residual_partition_order()... ");
+       if(!encoder->set_min_residual_partition_order(0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_max_residual_partition_order()... ");
+       if(!encoder->set_max_residual_partition_order(0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_rice_parameter_search_dist()... ");
+       if(!encoder->set_rice_parameter_search_dist(0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_total_samples_estimate()... ");
+       if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing set_metadata()... ");
+       if(!encoder->set_metadata(metadata_sequence_, num_metadata_))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILENAME) {
+               printf("opening file for FLAC output... ");
+               file = ::fopen(flacfilename(is_ogg), "w+b");
+               if(0 == file) {
+                       printf("ERROR (%s)\n", strerror(errno));
+                       return false;
+               }
+               printf("OK\n");
+               if(layer < LAYER_FILE)
+                       dynamic_cast<StreamEncoder*>(encoder)->file_ = file;
+       }
+
+       switch(layer) {
+               case LAYER_STREAM:
+               case LAYER_SEEKABLE_STREAM:
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg? encoder->init_ogg() : encoder->init();
+                       break;
+               case LAYER_FILE:
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg?
+                               dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(file) :
+                               dynamic_cast<FLAC::Encoder::File*>(encoder)->init(file);
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing init%s()... ", is_ogg? "_ogg":"");
+                       init_status = is_ogg?
+                               dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(flacfilename(is_ogg)) :
+                               dynamic_cast<FLAC::Encoder::File*>(encoder)->init(flacfilename(is_ogg));
+                       break;
+               default:
+                       die_("internal error 001");
+                       return false;
+       }
+       if(init_status != ::FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+               return die_s_(0, encoder);
+       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_verify_decoder_state()... ");
+       FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
+       printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing get_verify_decoder_error_stats()... ");
+               encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing get_verify()... ");
+       if(encoder->get_verify() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_streamable_subset()... ");
+       if(encoder->get_streamable_subset() != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_mid_side_stereo()... ");
+       if(encoder->get_do_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_loose_mid_side_stereo()... ");
+       if(encoder->get_loose_mid_side_stereo() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_channels()... ");
+       if(encoder->get_channels() != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_bits_per_sample()... ");
+       if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_sample_rate()... ");
+       if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_blocksize()... ");
+       if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_lpc_order()... ");
+       if(encoder->get_max_lpc_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_lpc_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_qlp_coeff_precision()... ");
+       (void)encoder->get_qlp_coeff_precision();
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing get_do_qlp_coeff_prec_search()... ");
+       if(encoder->get_do_qlp_coeff_prec_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_escape_coding()... ");
+       if(encoder->get_do_escape_coding() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_do_exhaustive_model_search()... ");
+       if(encoder->get_do_exhaustive_model_search() != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_min_residual_partition_order()... ");
+       if(encoder->get_min_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_min_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_max_residual_partition_order()... ");
+       if(encoder->get_max_residual_partition_order() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_residual_partition_order());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_rice_parameter_search_dist()... ");
+       if(encoder->get_rice_parameter_search_dist() != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, encoder->get_rice_parameter_search_dist());
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing get_total_samples_estimate()... ");
+       if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
+#ifdef _MSC_VER
+               printf("FAILED, expected %I64u, got %I64u\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
+#else
+               printf("FAILED, expected %llu, got %llu\n", (unsigned long long)streaminfo_.data.stream_info.total_samples, (unsigned long long)encoder->get_total_samples_estimate());
+#endif
+               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 die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing process_interleaved()... ");
+       if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing finish()... ");
+       if(!encoder->finish()) {
+               FLAC::Encoder::Stream::State state = encoder->get_state();
+               printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
+               return false;
+       }
+       printf("OK\n");
+
+       if(layer < LAYER_FILE)
+               ::fclose(dynamic_cast<StreamEncoder*>(encoder)->file_);
+
+       printf("freeing encoder instance... ");
+       delete encoder;
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+bool test_encoders()
+{
+       FLAC__bool is_ogg = false;
+
+       while(1) {
+               init_metadata_blocks_();
+
+               if(!test_stream_encoder(LAYER_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_FILE, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
+                       return false;
+
+               (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+               free_metadata_blocks_();
+
+               if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+                       break;
+               is_ogg = true;
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC++/encoders.h b/src/test_libFLAC++/encoders.h
new file mode 100644 (file)
index 0000000..2b5c8c7
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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++/main.cpp b/src/test_libFLAC++/main.cpp
new file mode 100644 (file)
index 0000000..6a3a0a3
--- /dev/null
@@ -0,0 +1,37 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.cpp b/src/test_libFLAC++/metadata.cpp
new file mode 100644 (file)
index 0000000..135f61e
--- /dev/null
@@ -0,0 +1,36 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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 bool test_metadata_object();
+extern bool 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..090dcc4
--- /dev/null
@@ -0,0 +1,24 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.cpp b/src/test_libFLAC++/metadata_manip.cpp
new file mode 100644 (file)
index 0000000..27336f9
--- /dev/null
@@ -0,0 +1,2210 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod() */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#include "FLAC/assert.h"
+#include "FLAC++/decoder.h"
+#include "FLAC++/metadata.h"
+#include "share/grabbag.h"
+extern "C" {
+#include "test_libs_common/file_utils_flac.h"
+}
+
+/******************************************************************************
+       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::Decoder::File 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.
+******************************************************************************/
+
+class OurFileDecoder: public FLAC::Decoder::File {
+public:
+       inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }
+
+       bool ignore_metadata_;
+       bool error_occurred_;
+protected:
+       ::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);
+};
+
+struct OurMetadata {
+       FLAC::Metadata::Prototype *blocks[64];
+       unsigned num_blocks;
+};
+
+/* our copy of the metadata in flacfilename() */
+static OurMetadata 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 const char *flacfilename(bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
+{
+       printf("ERROR: %s\n", msg);
+       printf("       status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
+       return false;
+}
+
+static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
+{
+       const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
+       printf("ERROR: %s\n", msg);
+       printf("       status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
+       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 char *strdup_or_die_(const char *s)
+{
+       char *x = strdup(s);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+               exit(1);
+       }
+       return x;
+}
+
+/* functions for working with our metadata copy */
+
+static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
+{
+       unsigned i;
+       FLAC::Metadata::Prototype *obj = block;
+       FLAC__ASSERT(position < our_metadata_.num_blocks);
+       if(copy) {
+               if(0 == (obj = FLAC::Metadata::clone(block)))
+                       return die_("during FLAC::Metadata::clone()");
+       }
+       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]->set_is_last(false);
+       our_metadata_.blocks[i]->set_is_last(true);
+
+       return true;
+}
+
+static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
+{
+       unsigned i;
+       FLAC::Metadata::Prototype *obj = block;
+       if(copy) {
+               if(0 == (obj = FLAC::Metadata::clone(block)))
+                       return die_("during FLAC::Metadata::clone()");
+       }
+       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]->set_is_last(false);
+       our_metadata_.blocks[i]->set_is_last(true);
+
+       return true;
+}
+
+static void delete_from_our_metadata_(unsigned position)
+{
+       unsigned i;
+       FLAC__ASSERT(position < our_metadata_.num_blocks);
+       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]->set_is_last(false);
+               our_metadata_.blocks[i]->set_is_last(true);
+       }
+}
+
+void add_to_padding_length_(unsigned index, int delta)
+{
+       FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
+       FLAC__ASSERT(0 != padding);
+       padding->set_length((unsigned)((int)padding->get_length() + delta));
+}
+
+/*
+ * This wad of functions supports filename- and callback-based chain reading/writing.
+ * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
+ */
+bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+       static const char *tempfile_suffix = ".metadata_edit";
+
+       if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
+               return false;
+       strcpy(*tempfilename, filename);
+       strcat(*tempfilename, tempfile_suffix);
+
+       if(0 == (*tempfile = fopen(*tempfilename, "wb")))
+               return false;
+
+       return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+       if(0 != *tempfile) {
+               (void)fclose(*tempfile);
+               *tempfile = 0;
+       }
+
+       if(0 != *tempfilename) {
+               (void)unlink(*tempfilename);
+               free(*tempfilename);
+               *tempfilename = 0;
+       }
+}
+
+bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != tempfile);
+       FLAC__ASSERT(0 != tempfilename);
+       FLAC__ASSERT(0 != *tempfilename);
+
+       if(0 != *tempfile) {
+               (void)fclose(*tempfile);
+               *tempfile = 0;
+       }
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+       /* on some flavors of windows, rename() will fail if the destination already exists */
+       if(unlink(filename) < 0) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+#endif
+
+       if(0 != rename(*tempfilename, filename)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+
+       cleanup_tempfile_(tempfile, tempfilename);
+
+       return true;
+}
+
+bool get_file_stats_(const char *filename, struct stat *stats)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+       return (0 == stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct stat *stats)
+{
+       struct utimbuf srctime;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+
+       srctime.actime = stats->st_atime;
+       srctime.modtime = stats->st_mtime;
+       (void)chmod(filename, stats->st_mode);
+       (void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+       (void)chown(filename, stats->st_uid, (gid_t)(-1));
+       (void)chown(filename, (uid_t)(-1), stats->st_gid);
+#endif
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
+{
+       FILE *stream = (FILE*)handle;
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#endif
+
+static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+       off_t o = (off_t)offset;
+       FLAC__ASSERT(offset == o);
+       return fseeko((FILE*)handle, o, whence);
+}
+
+static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
+{
+       return ftello((FILE*)handle);
+}
+
+static int chain_eof_cb_(::FLAC__IOHandle handle)
+{
+       return feof((FILE*)handle);
+}
+
+static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
+{
+       if(filename_based)
+               return chain.write(use_padding, preserve_file_stats);
+       else {
+               ::FLAC__IOCallbacks callbacks;
+
+               memset(&callbacks, 0, sizeof(callbacks));
+               callbacks.read = (::FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+               callbacks.write = chain_write_cb_;
+#else
+               callbacks.write = (::FLAC__IOCallback_Write)fwrite;
+#endif
+               callbacks.seek = chain_seek_cb_;
+               callbacks.eof = chain_eof_cb_;
+
+               if(chain.check_if_tempfile_needed(use_padding)) {
+                       struct stat stats;
+                       FILE *file, *tempfile;
+                       char *tempfilename;
+                       if(preserve_file_stats) {
+                               if(!get_file_stats_(filename, &stats))
+                                       return false;
+                       }
+                       if(0 == (file = fopen(filename, "rb")))
+                               return false; /*@@@@ chain status still says OK though */
+                       if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
+                               fclose(file);
+                               cleanup_tempfile_(&tempfile, &tempfilename);
+                               return false; /*@@@@ chain status still says OK though */
+                       }
+                       if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
+                               fclose(file);
+                               fclose(tempfile);
+                               return false;
+                       }
+                       fclose(file);
+                       fclose(tempfile);
+                       file = tempfile = 0;
+                       if(!transport_tempfile_(filename, &tempfile, &tempfilename))
+                               return false;
+                       if(preserve_file_stats)
+                               set_file_stats_(filename, &stats);
+               }
+               else {
+                       FILE *file = fopen(filename, "r+b");
+                       if(0 == file)
+                               return false; /*@@@@ chain status still says OK though */
+                       if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
+                               return false;
+                       fclose(file);
+               }
+       }
+
+       return true;
+}
+
+static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg)
+{
+       if(filename_based)
+               return chain.read(filename, is_ogg);
+       else {
+               ::FLAC__IOCallbacks callbacks;
+
+               memset(&callbacks, 0, sizeof(callbacks));
+               callbacks.read = (::FLAC__IOCallback_Read)fread;
+               callbacks.seek = chain_seek_cb_;
+               callbacks.tell = chain_tell_cb_;
+
+               {
+                       bool ret;
+                       FILE *file = fopen(filename, "rb");
+                       if(0 == file)
+                               return false; /*@@@@ chain status still says OK though */
+                       ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg);
+                       fclose(file);
+                       return ret;
+               }
+       }
+}
+
+/* function for comparing our metadata to a FLAC::Metadata::Chain */
+
+static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
+{
+       unsigned i;
+       FLAC::Metadata::Iterator iterator;
+       bool next_ok = true;
+
+       printf("\tcomparing chain... ");
+       fflush(stdout);
+
+       if(!iterator.is_valid())
+               return die_("allocating memory for iterator");
+
+       iterator.init(chain);
+
+       i = 0;
+       do {
+               FLAC::Metadata::Prototype *block;
+
+               printf("%u... ", i);
+               fflush(stdout);
+
+               if(0 == (block = iterator.get_block()))
+                       return die_("getting block from iterator");
+
+               if(*block != *our_metadata_.blocks[i])
+                       return die_("metadata block mismatch");
+
+               delete block;
+               i++;
+               next_ok = iterator.next();
+       } while(i < our_metadata_.num_blocks && next_ok);
+
+       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(*current_block != *our_metadata_.blocks[current_position])
+                       return die_("metadata block mismatch");
+       }
+
+       printf("PASSED\n");
+
+       return true;
+}
+
+::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       (void)buffer;
+
+       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 OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
+{
+       /* don't bother checking if we've already hit an error */
+       if(error_occurred_)
+               return;
+
+       printf("%d... ", mc_our_block_number_);
+       fflush(stdout);
+
+       if(!ignore_metadata_) {
+               if(mc_our_block_number_ >= our_metadata_.num_blocks) {
+                       (void)die_("got more metadata blocks than expected");
+                       error_occurred_ = true;
+               }
+               else {
+                       if(*our_metadata_.blocks[mc_our_block_number_] != metadata) {
+                               (void)die_("metadata block mismatch");
+                               error_occurred_ = true;
+                       }
+               }
+       }
+
+       mc_our_block_number_++;
+}
+
+void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
+{
+       error_occurred_ = true;
+       printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
+}
+
+static bool generate_file_(bool include_extras, bool is_ogg)
+{
+       ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+       ::FLAC__StreamMetadata *metadata[4];
+       unsigned i = 0, n = 0;
+
+       printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
+
+       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);
+
+       {
+               const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+               vorbiscomment.is_last = false;
+               vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               vorbiscomment.length = (4 + vendor_string_length) + 4;
+               vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
+               vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+               memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+               vorbiscomment.data.vorbis_comment.num_comments = 0;
+               vorbiscomment.data.vorbis_comment.comments = 0;
+       }
+
+       {
+               if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
+                       return die_("priming our metadata");
+               cuesheet->is_last = false;
+               strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
+               cuesheet->data.cue_sheet.lead_in = 123;
+               cuesheet->data.cue_sheet.is_cd = false;
+               if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+                       return die_("priming our metadata");
+               cuesheet->data.cue_sheet.tracks[0].number = 1;
+               if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+                       return die_("priming our metadata");
+       }
+
+       {
+               picture.is_last = false;
+               picture.type = ::FLAC__METADATA_TYPE_PICTURE;
+               picture.length =
+                       (
+                               FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+                               FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+                               FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+                       ) / 8
+               ;
+               picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+               picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+               picture.length += strlen(picture.data.picture.mime_type);
+               picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+               picture.length += strlen((const char *)picture.data.picture.description);
+               picture.data.picture.width = 300;
+               picture.data.picture.height = 300;
+               picture.data.picture.depth = 24;
+               picture.data.picture.colors = 0;
+               picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+               picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+               picture.length += picture.data.picture.data_length;
+       }
+
+       padding.is_last = true;
+       padding.type = ::FLAC__METADATA_TYPE_PADDING;
+       padding.length = 1234;
+
+       metadata[n++] = &vorbiscomment;
+       if(include_extras) {
+               metadata[n++] = cuesheet;
+               metadata[n++] = &picture;
+       }
+       metadata[n++] = &padding;
+
+       FLAC::Metadata::StreamInfo s(&streaminfo);
+       FLAC::Metadata::VorbisComment v(&vorbiscomment);
+       FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
+       FLAC::Metadata::Picture pi(&picture);
+       FLAC::Metadata::Padding p(&padding);
+       if(
+               !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
+               !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
+               (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
+               (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
+               !insert_to_our_metadata_(&p, i++, /*copy=*/true)
+       )
+               return die_("priming our metadata");
+
+       if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
+               return die_("creating the encoded file");
+
+       free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
+       free(picture.data.picture.mime_type);
+       free(picture.data.picture.description);
+       free(picture.data.picture.data);
+
+       return true;
+}
+
+static bool test_file_(bool is_ogg, bool ignore_metadata)
+{
+       const char *filename = flacfilename(is_ogg);
+       OurFileDecoder decoder(ignore_metadata);
+
+       mc_our_block_number_ = 0;
+       decoder.error_occurred_ = false;
+
+       printf("\ttesting '%s'... ", filename);
+       fflush(stdout);
+
+       if(!decoder.is_valid())
+               return die_("couldn't allocate decoder instance");
+
+       decoder.set_md5_checking(true);
+       decoder.set_metadata_respond_all();
+       if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+               (void)decoder.finish();
+               return die_("initializing decoder\n");
+       }
+       if(!decoder.process_until_end_of_stream()) {
+               (void)decoder.finish();
+               return die_("decoding file\n");
+       }
+
+       (void)decoder.finish();
+
+       if(decoder.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 bool change_stats_(const char *filename, bool read_only)
+{
+       if(!grabbag__file_change_stats(filename, read_only))
+               return die_("during grabbag__file_change_stats()");
+
+       return true;
+}
+
+static bool remove_file_(const char *filename)
+{
+       while(our_metadata_.num_blocks > 0)
+               delete_from_our_metadata_(0);
+
+       if(!grabbag__file_remove_file(filename))
+               return die_("removing file");
+
+       return true;
+}
+
+static bool test_level_0_()
+{
+       FLAC::Metadata::StreamInfo streaminfo;
+
+       printf("\n\n++++++ testing level 0 interface\n");
+
+       if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
+               return false;
+
+       printf("testing FLAC::Metadata::get_streaminfo()... ");
+
+       if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo))
+               return die_("during FLAC::Metadata::get_streaminfo()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(streaminfo.get_channels() != 1)
+               return die_("mismatch in streaminfo.get_channels()");
+       if(streaminfo.get_bits_per_sample() != 8)
+               return die_("mismatch in streaminfo.get_bits_per_sample()");
+       if(streaminfo.get_sample_rate() != 44100)
+               return die_("mismatch in streaminfo.get_sample_rate()");
+       if(streaminfo.get_min_blocksize() != 576)
+               return die_("mismatch in streaminfo.get_min_blocksize()");
+       if(streaminfo.get_max_blocksize() != 576)
+               return die_("mismatch in streaminfo.get_max_blocksize()");
+
+       printf("OK\n");
+
+       {
+               printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... ");
+
+               FLAC::Metadata::VorbisComment *tags = 0;
+
+               if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
+                       return die_("during FLAC::Metadata::get_tags()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(tags->get_num_comments() != 0)
+                       return die_("mismatch in tags->get_num_comments()");
+
+               printf("OK\n");
+
+               delete tags;
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_tags(VorbisComment &)... ");
+
+               FLAC::Metadata::VorbisComment tags;
+
+               if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags))
+                       return die_("during FLAC::Metadata::get_tags()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(tags.get_num_comments() != 0)
+                       return die_("mismatch in tags.get_num_comments()");
+
+               printf("OK\n");
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
+
+               FLAC::Metadata::CueSheet *cuesheet = 0;
+
+               if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
+                       return die_("during FLAC::Metadata::get_cuesheet()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(cuesheet->get_lead_in() != 123)
+                       return die_("mismatch in cuesheet->get_lead_in()");
+
+               printf("OK\n");
+
+               delete cuesheet;
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
+
+               FLAC::Metadata::CueSheet cuesheet;
+
+               if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet))
+                       return die_("during FLAC::Metadata::get_cuesheet()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(cuesheet.get_lead_in() != 123)
+                       return die_("mismatch in cuesheet.get_lead_in()");
+
+               printf("OK\n");
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
+
+               FLAC::Metadata::Picture *picture = 0;
+
+               if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
+                       return die_("during FLAC::Metadata::get_picture()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+                       return die_("mismatch in picture->get_type ()");
+
+               printf("OK\n");
+
+               delete picture;
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_picture(Picture &)... ");
+
+               FLAC::Metadata::Picture picture;
+
+               if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
+                       return die_("during FLAC::Metadata::get_picture()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+                       return die_("mismatch in picture->get_type ()");
+
+               printf("OK\n");
+       }
+
+       if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+               return false;
+
+       return true;
+}
+
+static bool test_level_1_()
+{
+       FLAC::Metadata::Prototype *block;
+       FLAC::Metadata::StreamInfo *streaminfo;
+       FLAC::Metadata::Padding *padding;
+       FLAC::Metadata::Application *app;
+       FLAC__byte data[1000];
+       unsigned our_current_position = 0;
+
+       // initialize 'data' to avoid Valgrind errors
+       memset(data, 0, sizeof(data));
+
+       printf("\n\n++++++ testing level 1 interface\n");
+
+       /************************************************************/
+       {
+       printf("simple iterator on read-only file\n");
+
+       if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
+               return false;
+
+       if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true))
+               return false;
+
+       FLAC::Metadata::SimpleIterator iterator;
+
+       if(!iterator.is_valid())
+               return die_("iterator.is_valid() returned false");
+
+       if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+               return die_("iterator.init() returned false");
+
+       printf("is writable = %u\n", (unsigned)iterator.is_writable());
+       if(iterator.is_writable())
+               return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
+
+       printf("iterate forwards\n");
+
+       if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
+               return die_("expected STREAMINFO type from iterator.get_block_type()");
+       if(0 == (block = iterator.get_block()))
+               return die_("getting block 0");
+       if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO)
+               return die_("expected STREAMINFO type");
+       if(block->get_is_last())
+               return die_("expected is_last to be false");
+       if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+               return die_("bad STREAMINFO length");
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+       FLAC__ASSERT(0 != streaminfo);
+       if(streaminfo->get_channels() != 1)
+               return die_("mismatch in channels");
+       if(streaminfo->get_bits_per_sample() != 8)
+               return die_("mismatch in bits_per_sample");
+       if(streaminfo->get_sample_rate() != 44100)
+               return die_("mismatch in sample_rate");
+       if(streaminfo->get_min_blocksize() != 576)
+               return die_("mismatch in min_blocksize");
+       if(streaminfo->get_max_blocksize() != 576)
+               return die_("mismatch in max_blocksize");
+       // we will delete streaminfo a little later when we're really done with it...
+
+       if(!iterator.next())
+               return die_("forward iterator ended early");
+       our_current_position++;
+
+       if(!iterator.next())
+               return die_("forward iterator ended early");
+       our_current_position++;
+
+       if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING)
+               return die_("expected PADDING type from iterator.get_block_type()");
+       if(0 == (block = iterator.get_block()))
+               return die_("getting block 1");
+       if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING)
+               return die_("expected PADDING type");
+       if(!block->get_is_last())
+               return die_("expected is_last to be true");
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(block->get_length() != 1234)
+               return die_("bad PADDING length");
+       delete block;
+
+       if(iterator.next())
+               return die_("forward iterator returned true but should have returned false");
+
+       printf("iterate backwards\n");
+       if(!iterator.prev())
+               return die_("reverse iterator ended early");
+       if(!iterator.prev())
+               return die_("reverse iterator ended early");
+       if(iterator.prev())
+               return die_("reverse iterator returned true but should have returned false");
+
+       printf("testing iterator.set_block() on read-only file...\n");
+
+       if(!iterator.set_block(streaminfo, false))
+               printf("PASSED.  iterator.set_block() returned false like it should\n");
+       else
+               return die_("iterator.set_block() returned true but shouldn't have");
+       delete streaminfo;
+       }
+
+       /************************************************************/
+       {
+       printf("simple iterator on writable file\n");
+
+       if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
+               return false;
+
+       printf("creating APPLICATION block\n");
+
+       if(0 == (app = new FLAC::Metadata::Application()))
+               return die_("new FLAC::Metadata::Application()");
+       app->set_id((const unsigned char *)"duh");
+
+       printf("creating PADDING block\n");
+
+       if(0 == (padding = new FLAC::Metadata::Padding()))
+               return die_("new FLAC::Metadata::Padding()");
+       padding->set_length(20);
+
+       FLAC::Metadata::SimpleIterator iterator;
+
+       if(!iterator.is_valid())
+               return die_("iterator.is_valid() returned false");
+
+       if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+               return die_("iterator.init() returned false");
+       our_current_position = 0;
+
+       printf("is writable = %u\n", (unsigned)iterator.is_writable());
+
+       printf("[S]VP\ttry to write over STREAMINFO block...\n");
+       if(!iterator.set_block(app, false))
+               printf("\titerator.set_block() returned false like it should\n");
+       else
+               return die_("iterator.set_block() returned true but shouldn't have");
+
+       printf("[S]VP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
+       padding->set_length(25);
+       if(!iterator.insert_block_after(padding, false))
+               return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       printf("SVP[P]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[P]P\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
+       padding->set_length(30);
+       if(!iterator.insert_block_after(padding, false))
+               return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[P]PP\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]PPP\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
+       if(iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false) should have returned false", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("[S]VPPP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]PPP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]PP\tdelete (middle block), replace with padding\n");
+       if(!iterator.delete_block(true))
+               return die_ss_("iterator.delete_block(true)", iterator);
+       our_current_position--;
+
+       printf("S[V]PPP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]PP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]\tdelete (last block), replace with padding\n");
+       if(!iterator.delete_block(true))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       our_current_position--;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[P]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]\tdelete (last block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[P]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]P\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VP\tset STREAMINFO (change sample rate)\n");
+       FLAC__ASSERT(our_current_position == 0);
+       block = iterator.get_block();
+       streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+       FLAC__ASSERT(0 != streaminfo);
+       streaminfo->set_sample_rate(32000);
+       if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(block, false))
+               return die_ss_("iterator.set_block(block, false)", iterator);
+       delete block;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("[S]VP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
+       app->set_id((const unsigned char *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */
+       if(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return false;
+       add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
+       app->set_id((const unsigned char *)"fuh"); /* twiddle the id */
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+       if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
+               return false;
+       add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length()));
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
+       app->set_id((const unsigned char *)"guh"); /* twiddle the id */
+       if(!app->set_data(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(!iterator.set_block(app, false))
+               return die_ss_("iterator.set_block(app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
+       app->set_id((const unsigned char *)"huh"); /* twiddle the id */
+       if(!app->set_data(data, 12, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app, false))
+               return die_ss_("iterator.set_block(app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
+       app->set_id((const unsigned char *)"iuh"); /* twiddle the id */
+       if(!app->set_data(data, sizeof(data), true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12));
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
+       app->set_id((const unsigned char *)"juh"); /* twiddle the id */
+       if(!app->set_data(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");
+       dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH);
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]PP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVAA[P]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
+       padding->set_length(5);
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(padding, false))
+               return die_ss_("iterator.set_block(padding, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVAAP[P]\tset APPLICATION (grow)\n");
+       app->set_id((const unsigned char *)"kuh"); /* twiddle the id */
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app, false))
+               return die_ss_("iterator.set_block(app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVAAP[A]\tset PADDING (equal)\n");
+       padding->set_length(27);
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(padding, false))
+               return die_ss_("iterator.set_block(padding, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVAAP[P]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVA[P]\tinsert PADDING after\n");
+       padding->set_length(5);
+       if(!iterator.insert_block_after(padding, false))
+               return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVAP[P]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVA[P]P\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
+       if(!app->set_data(data, 32, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
+       if(!app->set_data(data, 60, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
+       if(!app->set_data(data, 87, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+       if(!app->set_data(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(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+       if(!app->set_data(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]->set_is_last(true);
+       if(!iterator.set_block(app, true))
+               return die_ss_("iterator.set_block(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tset PADDING (equal size)\n");
+       padding->set_length(app->get_length());
+       if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(padding, true))
+               return die_ss_("iterator.set_block(padding, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[P]\tinsert PADDING after\n");
+       if(!iterator.insert_block_after(padding, false))
+               return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVP[P]\tinsert PADDING after\n");
+       padding->set_length(5);
+       if(!iterator.insert_block_after(padding, false))
+               return die_ss_("iterator.insert_block_after(padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVPP[P]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVP[P]P\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[P]PP\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
+       if(!app->set_data(data, 101, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
+       if(!app->set_data(data, 97, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+       if(!app->set_data(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(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
+       if(!app->set_data(data, 96, true))
+               return die_("setting APPLICATION data");
+       if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+               return die_("copying object");
+       dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(0);
+       if(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]PP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!iterator.delete_block(false))
+               return die_ss_("iterator.delete_block(false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+
+       printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+       if(!app->set_data(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(!iterator.insert_block_after(app, true))
+               return die_ss_("iterator.insert_block_after(app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false))
+               return false;
+       }
+
+       delete app;
+       delete padding;
+
+       if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+               return false;
+
+       return true;
+}
+
+static bool test_level_2_(bool filename_based, bool is_ogg)
+{
+       FLAC::Metadata::Prototype *block;
+       FLAC::Metadata::StreamInfo *streaminfo;
+       FLAC::Metadata::Application *app;
+       FLAC::Metadata::Padding *padding;
+       FLAC__byte data[2000];
+       unsigned our_current_position;
+
+       // initialize 'data' to avoid Valgrind errors
+       memset(data, 0, sizeof(data));
+
+       printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
+
+       printf("generate read-only file\n");
+
+       if(!generate_file_(/*include_extras=*/false, is_ogg))
+               return false;
+
+       if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
+               return false;
+
+       printf("create chain\n");
+       FLAC::Metadata::Chain chain;
+       if(!chain.is_valid())
+               return die_("allocating memory for chain");
+
+       printf("read chain\n");
+
+       if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
+               return die_c_("reading chain", chain.status());
+
+       printf("[S]VP\ttest initial metadata\n");
+
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       if(is_ogg)
+               goto end;
+
+       printf("switch file to read-write\n");
+
+       if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
+               return false;
+
+       printf("create iterator\n");
+       {
+       FLAC::Metadata::Iterator iterator;
+       if(!iterator.is_valid())
+               return die_("allocating memory for iterator");
+
+       our_current_position = 0;
+
+       iterator.init(chain);
+
+       if(0 == (block = iterator.get_block()))
+               return die_("getting block from iterator");
+
+       FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO);
+
+       printf("[S]VP\tmodify STREAMINFO, write\n");
+
+       streaminfo = dynamic_cast<FLAC::Metadata::StreamInfo *>(block);
+       FLAC__ASSERT(0 != streaminfo);
+       streaminfo->set_sample_rate(32000);
+       if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       delete block;
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, true)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("[S]VP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
+       if(0 == (block = iterator.get_block()))
+               return die_("getting block from iterator");
+       if(0 == (app = new FLAC::Metadata::Application()))
+               return die_("new FLAC::Metadata::Application()");
+       app->set_id((const unsigned char *)"duh");
+       if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
+               return die_("setting APPLICATION data");
+       delete block;
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tshrink APPLICATION, don't use padding\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 26, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tgrow APPLICATION, don't use padding\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 28, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 36, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 33, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
+       if(0 == (padding = new FLAC::Metadata::Padding()))
+               return die_("creating PADDING block");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 29, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       padding->set_length(0);
+       if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
+               return die_("internal error");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 16, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[our_current_position+1])->set_length(13);
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 50, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(data, 56, true))
+               return die_("setting APPLICATION data");
+       if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+               return die_("copying object");
+       add_to_padding_length_(our_current_position+1, -(56 - 50));
+       if(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+       if(0 == (app = dynamic_cast<FLAC::Metadata::Application *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("copying object");
+       if(!app->set_data(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(!iterator.set_block(app))
+               return die_c_("iterator.set_block(app)", chain.status());
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV[A]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]A\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
+       if(0 == (padding = new FLAC::Metadata::Padding()))
+               return die_("creating PADDING block");
+       padding->set_length(30);
+       if(!iterator.insert_block_before(padding))
+               printf("\titerator.insert_block_before() returned false like it should\n");
+       else
+               return die_("iterator.insert_block_before() should have returned false");
+
+       printf("[S]VA\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]A\tinsert PADDING after\n");
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!iterator.insert_block_after(padding))
+               return die_("iterator.insert_block_after(padding)");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("SV[P]A\tinsert PADDING before\n");
+       if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("creating PADDING block");
+       padding->set_length(17);
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!iterator.insert_block_before(padding))
+               return die_("iterator.insert_block_before(padding)");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("SV[P]PA\tinsert PADDING before\n");
+       if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position]))))
+               return die_("creating PADDING block");
+       padding->set_length(0);
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!iterator.insert_block_before(padding))
+               return die_("iterator.insert_block_before(padding)");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("SV[P]PPA\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]PA\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVPP[P]A\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVPPP[A]\tinsert PADDING after\n");
+       if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
+               return die_("creating PADDING block");
+       padding->set_length(57);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!iterator.insert_block_after(padding))
+               return die_("iterator.insert_block_after(padding)");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("SVPPPA[P]\tinsert PADDING before\n");
+       if(0 == (padding = dynamic_cast<FLAC::Metadata::Padding *>(FLAC::Metadata::clone(our_metadata_.blocks[2]))))
+               return die_("creating PADDING block");
+       padding->set_length(99);
+       if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+               return die_("copying metadata");
+       if(!iterator.insert_block_before(padding))
+               return die_("iterator.insert_block_before(padding)");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       }
+       our_current_position = 0;
+
+       printf("SVPPPAPP\tmerge padding\n");
+       chain.merge_padding();
+       add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length());
+       add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length());
+       add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length());
+       delete_from_our_metadata_(7);
+       delete_from_our_metadata_(4);
+       delete_from_our_metadata_(3);
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SVPAP\tsort padding\n");
+       chain.sort_padding();
+       add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length());
+       delete_from_our_metadata_(2);
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(true, false)", chain.status());
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("create iterator\n");
+       {
+       FLAC::Metadata::Iterator iterator;
+       if(!iterator.is_valid())
+               return die_("allocating memory for iterator");
+
+       our_current_position = 0;
+
+       iterator.init(chain);
+
+       printf("[S]VAP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]AP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[A]P\tdelete middle block, replace with padding\n");
+       if(0 == (padding = new FLAC::Metadata::Padding()))
+               return die_("creating PADDING block");
+       padding->set_length(71);
+       if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+               return die_("copying object");
+       if(!iterator.delete_block(/*replace_with_padding=*/true))
+               return die_c_("iterator.delete_block(true)", chain.status());
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("S[V]PP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]P\tdelete middle block, don't replace with padding\n");
+       delete_from_our_metadata_(our_current_position--);
+       if(!iterator.delete_block(/*replace_with_padding=*/false))
+               return die_c_("iterator.delete_block(false)", chain.status());
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("S[V]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]\tdelete last block, replace with padding\n");
+       if(0 == (padding = new FLAC::Metadata::Padding()))
+               return die_("creating PADDING block");
+       padding->set_length(219);
+       if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+               return die_("copying object");
+       if(!iterator.delete_block(/*replace_with_padding=*/true))
+               return die_c_("iterator.delete_block(true)", chain.status());
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("S[V]P\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]\tdelete last block, don't replace with padding\n");
+       delete_from_our_metadata_(our_current_position--);
+       if(!iterator.delete_block(/*replace_with_padding=*/false))
+               return die_c_("iterator.delete_block(false)", chain.status());
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       printf("S[V]\tprev\n");
+       if(!iterator.prev())
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]V\tdelete STREAMINFO block, should fail\n");
+       if(iterator.delete_block(/*replace_with_padding=*/false))
+               return die_("iterator.delete_block() on STREAMINFO should have failed but didn't");
+
+       block = iterator.get_block();
+       if(!compare_chain_(chain, our_current_position, block))
+               return false;
+       delete block;
+
+       } // delete iterator
+       our_current_position = 0;
+
+       printf("SV\tmerge padding\n");
+       chain.merge_padding();
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+       printf("SV\tsort padding\n");
+       chain.sort_padding();
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               return die_c_("during chain.write(false, false)", chain.status());
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, /*ignore_metadata=*/false))
+               return false;
+
+end:
+       if(!remove_file_(flacfilename(is_ogg)))
+               return false;
+
+       return true;
+}
+
+static bool test_level_2_misc_(bool is_ogg)
+{
+       ::FLAC__IOCallbacks callbacks;
+
+       memset(&callbacks, 0, sizeof(callbacks));
+       callbacks.read = (::FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+       callbacks.write = chain_write_cb_;
+#else
+       callbacks.write = (::FLAC__IOCallback_Write)fwrite;
+#endif
+       callbacks.seek = chain_seek_cb_;
+       callbacks.tell = chain_tell_cb_;
+       callbacks.eof = chain_eof_cb_;
+
+       printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
+
+       printf("generate file\n");
+
+       if(!generate_file_(/*include_extras=*/false, is_ogg))
+               return false;
+
+       printf("create chain\n");
+       FLAC::Metadata::Chain chain;
+       if(!chain.is_valid())
+               return die_("allocating chain");
+
+       printf("read chain (filename-based)\n");
+
+       if(!chain.read(flacfilename(is_ogg)))
+               return die_c_("reading chain", chain.status());
+
+       printf("write chain with wrong method Chain::write(with callbacks)\n");
+       {
+               if(chain.write(/*use_padding=*/false, 0, callbacks))
+                       return die_c_("mismatched write should have failed", chain.status());
+               if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+               printf("  OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (filename-based)\n");
+
+       if(!chain.read(flacfilename(is_ogg)))
+               return die_c_("reading chain", chain.status());
+
+       printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
+       {
+               if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
+                       return die_c_("mismatched write should have failed", chain.status());
+               if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+               printf("  OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", chain.status());
+               }
+               fclose(file);
+       }
+
+       printf("write chain with wrong method write()\n");
+       {
+               if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false))
+                       return die_c_("mismatched write should have failed", chain.status());
+               if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status());
+               printf("  OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", chain.status());
+               }
+               fclose(file);
+       }
+
+       printf("testing Chain::check_if_tempfile_needed()... ");
+
+       if(!chain.check_if_tempfile_needed(/*use_padding=*/false))
+               printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n");
+       else
+               return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have");
+
+       printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n");
+       {
+               if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks))
+                       return die_c_("mismatched write should have failed", chain.status());
+               if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
+               printf("  OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!chain.read((::FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", chain.status());
+               }
+               fclose(file);
+       }
+
+       printf("create iterator\n");
+       {
+       FLAC::Metadata::Iterator iterator;
+       if(!iterator.is_valid())
+               return die_("allocating memory for iterator");
+
+       iterator.init(chain);
+
+       printf("[S]VP\tnext\n");
+       if(!iterator.next())
+               return die_("iterator ended early\n");
+
+       printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
+       if(!iterator.delete_block(/*replace_with_padding=*/false))
+               return die_c_("block delete failed\n", chain.status());
+
+       printf("testing Chain::check_if_tempfile_needed()... ");
+
+       if(chain.check_if_tempfile_needed(/*use_padding=*/false))
+               printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n");
+       else
+               return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have");
+
+       printf("write chain with wrong method Chain::write(with callbacks)\n");
+       {
+               if(chain.write(/*use_padding=*/false, 0, callbacks))
+                       return die_c_("mismatched write should have failed", chain.status());
+               if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status());
+               printf("  OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+       }
+
+       } // delete iterator
+
+       if(!remove_file_(flacfilename(is_ogg)))
+               return false;
+
+       return true;
+}
+
+bool test_metadata_file_manipulation()
+{
+       printf("\n+++ libFLAC++ 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_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
+               return false;
+       if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
+               return false;
+       if(!test_level_2_misc_(/*is_ogg=*/false))
+               return false;
+
+       if(FLAC_API_SUPPORTS_OGG_FLAC) {
+               if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
+                       return false;
+               if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
+                       return false;
+#if 0
+               /* when ogg flac write is supported, will have to add this: */
+               if(!test_level_2_misc_(/*is_ogg=*/true))
+                       return false;
+#endif
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC++/metadata_object.cpp b/src/test_libFLAC++/metadata_object.cpp
new file mode 100644 (file)
index 0000000..9e9aec4
--- /dev/null
@@ -0,0 +1,2093 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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_, cuesheet_, picture_;
+
+static bool die_(const char *msg)
+{
+       printf("FAILED, %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 char *strdup_or_die_(const char *s)
+{
+       char *x = strdup(s);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+               exit(1);
+       }
+       return x;
+}
+
+static bool index_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Index &index, const ::FLAC__StreamMetadata_CueSheet_Index &indexcopy)
+{
+       if(indexcopy.offset != index.offset)
+               return false;
+       if(indexcopy.number != index.number)
+               return false;
+       return true;
+}
+
+static bool track_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Track *track, const ::FLAC__StreamMetadata_CueSheet_Track *trackcopy)
+{
+       unsigned i;
+
+       if(trackcopy->offset != track->offset)
+               return false;
+       if(trackcopy->number != track->number)
+               return false;
+       if(0 != strcmp(trackcopy->isrc, track->isrc))
+               return false;
+       if(trackcopy->type != track->type)
+               return false;
+       if(trackcopy->pre_emphasis != track->pre_emphasis)
+               return false;
+       if(trackcopy->num_indices != track->num_indices)
+               return false;
+       if(0 == track->indices || 0 == trackcopy->indices) {
+               if(track->indices != trackcopy->indices)
+                       return false;
+       }
+       else {
+               for(i = 0; i < track->num_indices; i++) {
+                       if(!index_is_equal_(trackcopy->indices[i], track->indices[i]))
+                               return false;
+               }
+       }
+       return true;
+}
+
+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 = false;
+       vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
+       vorbiscomment_.length = (4 + 5) + 4 + (4 + 12) + (4 + 12);
+       vorbiscomment_.data.vorbis_comment.vendor_string.length = 5;
+       vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(5+1);
+       memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "name0", 5+1);
+       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 = 12;
+       vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(12+1);
+       memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "name2=value2", 12+1);
+       vorbiscomment_.data.vorbis_comment.comments[1].length = 12;
+       vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1);
+       memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1);
+
+       cuesheet_.is_last = false;
+       cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET;
+       cuesheet_.length =
+               /* cuesheet guts */
+               (
+                       FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+               ) / 8 +
+               /* 2 tracks */
+               2 * (
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+               ) / 8 +
+               /* 3 index points */
+               3 * (
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+               ) / 8
+       ;
+       memset(cuesheet_.data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet_.data.cue_sheet.media_catalog_number));
+       cuesheet_.data.cue_sheet.media_catalog_number[0] = 'j';
+       cuesheet_.data.cue_sheet.media_catalog_number[1] = 'C';
+       cuesheet_.data.cue_sheet.lead_in = 159;
+       cuesheet_.data.cue_sheet.is_cd = true;
+       cuesheet_.data.cue_sheet.num_tracks = 2;
+       cuesheet_.data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)malloc_or_die_(cuesheet_.data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track));
+       cuesheet_.data.cue_sheet.tracks[0].offset = 1;
+       cuesheet_.data.cue_sheet.tracks[0].number = 1;
+       memcpy(cuesheet_.data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet_.data.cue_sheet.tracks[0].isrc));
+       cuesheet_.data.cue_sheet.tracks[0].type = 0;
+       cuesheet_.data.cue_sheet.tracks[0].pre_emphasis = 1;
+       cuesheet_.data.cue_sheet.tracks[0].num_indices = 2;
+       cuesheet_.data.cue_sheet.tracks[0].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+       cuesheet_.data.cue_sheet.tracks[0].indices[0].offset = 0;
+       cuesheet_.data.cue_sheet.tracks[0].indices[0].number = 0;
+       cuesheet_.data.cue_sheet.tracks[0].indices[1].offset = 1234567890;
+       cuesheet_.data.cue_sheet.tracks[0].indices[1].number = 1;
+       cuesheet_.data.cue_sheet.tracks[1].offset = 2345678901u;
+       cuesheet_.data.cue_sheet.tracks[1].number = 2;
+       memcpy(cuesheet_.data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet_.data.cue_sheet.tracks[1].isrc));
+       cuesheet_.data.cue_sheet.tracks[1].type = 1;
+       cuesheet_.data.cue_sheet.tracks[1].pre_emphasis = 0;
+       cuesheet_.data.cue_sheet.tracks[1].num_indices = 1;
+       cuesheet_.data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+       cuesheet_.data.cue_sheet.tracks[1].indices[0].offset = 0;
+       cuesheet_.data.cue_sheet.tracks[1].indices[0].number = 1;
+
+       picture_.is_last = true;
+       picture_.type = FLAC__METADATA_TYPE_PICTURE;
+       picture_.length =
+               (
+                       FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+                       FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+                       FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+               ) / 8
+       ;
+       picture_.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+       picture_.data.picture.mime_type = strdup_or_die_("image/jpeg");
+       picture_.length += strlen(picture_.data.picture.mime_type);
+       picture_.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+       picture_.length += strlen((const char *)picture_.data.picture.description);
+       picture_.data.picture.width = 300;
+       picture_.data.picture.height = 300;
+       picture_.data.picture.depth = 24;
+       picture_.data.picture.colors = 0;
+       picture_.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+       picture_.data.picture.data_length = strlen((const char *)picture_.data.picture.data);
+       picture_.length += picture_.data.picture.data_length;
+}
+
+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[1].entry);
+       free(vorbiscomment_.data.vorbis_comment.comments);
+       free(cuesheet_.data.cue_sheet.tracks[0].indices);
+       free(cuesheet_.data.cue_sheet.tracks[1].indices);
+       free(cuesheet_.data.cue_sheet.tracks);
+       free(picture_.data.picture.mime_type);
+       free(picture_.data.picture.description);
+       free(picture_.data.picture.data);
+}
+
+bool test_metadata_object_streaminfo()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::StreamInfo\n");
+
+       printf("testing StreamInfo::StreamInfo()... ");
+       FLAC::Metadata::StreamInfo block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       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 StreamInfo::StreamInfo(const StreamInfo &)... +\n");
+       printf("        StreamInfo::operator!=(const StreamInfo &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing StreamInfo::~StreamInfo()... ");
+       }
+       printf("OK\n");
+
+       printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(streaminfo_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(&streaminfo_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_);
+               FLAC::Metadata::StreamInfo blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy;
+               blockcopy.assign(&streaminfo_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_);
+               FLAC::Metadata::StreamInfo blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != streaminfo_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::operator=(const StreamInfo &)... +\n");
+       printf("        StreamInfo::operator==(const StreamInfo &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        StreamInfo::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy = streaminfo_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == streaminfo_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        StreamInfo::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::StreamInfo blockcopy = &streaminfo_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == streaminfo_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing StreamInfo::set_min_blocksize()... ");
+       block.set_min_blocksize(streaminfo_.data.stream_info.min_blocksize);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_max_blocksize()... ");
+       block.set_max_blocksize(streaminfo_.data.stream_info.max_blocksize);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_min_framesize()... ");
+       block.set_min_framesize(streaminfo_.data.stream_info.min_framesize);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_max_framesize()... ");
+       block.set_max_framesize(streaminfo_.data.stream_info.max_framesize);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_sample_rate()... ");
+       block.set_sample_rate(streaminfo_.data.stream_info.sample_rate);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_channels()... ");
+       block.set_channels(streaminfo_.data.stream_info.channels);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_bits_per_sample()... ");
+       block.set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_total_samples()... ");
+       block.set_total_samples(streaminfo_.data.stream_info.total_samples);
+       printf("OK\n");
+
+       printf("testing StreamInfo::set_md5sum()... ");
+       block.set_md5sum(streaminfo_.data.stream_info.md5sum);
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_min_blocksize()... ");
+       if(block.get_min_blocksize() != streaminfo_.data.stream_info.min_blocksize)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_max_blocksize()... ");
+       if(block.get_max_blocksize() != streaminfo_.data.stream_info.max_blocksize)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_min_framesize()... ");
+       if(block.get_min_framesize() != streaminfo_.data.stream_info.min_framesize)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_max_framesize()... ");
+       if(block.get_max_framesize() != streaminfo_.data.stream_info.max_framesize)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_sample_rate()... ");
+       if(block.get_sample_rate() != streaminfo_.data.stream_info.sample_rate)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_channels()... ");
+       if(block.get_channels() != streaminfo_.data.stream_info.channels)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_bits_per_sample()... ");
+       if(block.get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_total_samples()... ");
+       if(block.get_total_samples() != streaminfo_.data.stream_info.total_samples)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing StreamInfo::get_md5sum()... ");
+       if(0 != memcmp(block.get_md5sum(), streaminfo_.data.stream_info.md5sum, 16))
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::StreamInfo *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::StreamInfo *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing StreamInfo::~StreamInfo()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_padding()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::Padding\n");
+
+       printf("testing Padding::Padding()... ");
+       FLAC::Metadata::Padding block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = 0;
+       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 Padding::Padding(const Padding &)... +\n");
+       printf("        Padding::operator!=(const Padding &)... ");
+       {
+               FLAC::Metadata::Padding blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing Padding::~Padding()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Padding::Padding(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Padding blockcopy(padding_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::Padding(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Padding blockcopy(&padding_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Padding blockcopy(&padding_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_);
+               FLAC::Metadata::Padding blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Padding blockcopy;
+               blockcopy.assign(&padding_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Padding::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_);
+               FLAC::Metadata::Padding blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != padding_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::operator=(const Padding &)... +\n");
+       printf("        Padding::operator==(const Padding &)... ");
+       {
+               FLAC::Metadata::Padding blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Padding::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Padding blockcopy = padding_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == padding_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Padding::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Padding blockcopy = &padding_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == padding_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Padding::set_length()... ");
+       block.set_length(padding_.length);
+       printf("OK\n");
+
+       printf("testing Prototype::get_length()... ");
+       if(block.get_length() != padding_.length)
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::Padding *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::Padding *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing Padding::~Padding()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_application()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::Application\n");
+
+       printf("testing Application::Application()... ");
+       FLAC::Metadata::Application block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+       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 Application::Application(const Application &)... +\n");
+       printf("        Application::operator!=(const Application &)... ");
+       {
+               FLAC::Metadata::Application blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing Application::~Application()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Application::Application(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Application blockcopy(application_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::Application(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Application blockcopy(&application_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Application blockcopy(&application_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_);
+               FLAC::Metadata::Application blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Application blockcopy;
+               blockcopy.assign(&application_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Application::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_);
+               FLAC::Metadata::Application blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != application_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::operator=(const Application &)... +\n");
+       printf("        Application::operator==(const Application &)... ");
+       {
+               FLAC::Metadata::Application blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Application::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Application blockcopy = application_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == application_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Application::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Application blockcopy = &application_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == application_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Application::set_id()... ");
+       block.set_id(application_.data.application.id);
+       printf("OK\n");
+
+       printf("testing Application::set_data()... ");
+       block.set_data(application_.data.application.data, application_.length - sizeof(application_.data.application.id), /*copy=*/true);
+       printf("OK\n");
+
+       printf("testing Application::get_id()... ");
+       if(0 != memcmp(block.get_id(), application_.data.application.id, sizeof(application_.data.application.id)))
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing Application::get_data()... ");
+       if(0 != memcmp(block.get_data(), application_.data.application.data, application_.length - sizeof(application_.data.application.id)))
+               return die_("value mismatch, doesn't match previously set value");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::Application *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::Application *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing Application::~Application()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_seektable()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::SeekTable\n");
+
+       printf("testing SeekTable::SeekTable()... ");
+       FLAC::Metadata::SeekTable block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = 0;
+       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 SeekTable::SeekTable(const SeekTable &)... +\n");
+       printf("        SeekTable::operator!=(const SeekTable &)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing SeekTable::~SeekTable()... ");
+       }
+       printf("OK\n");
+
+       printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy(seektable_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy(&seektable_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy(&seektable_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_);
+               FLAC::Metadata::SeekTable blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy;
+               blockcopy.assign(&seektable_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        SeekTable::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_);
+               FLAC::Metadata::SeekTable blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != seektable_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::operator=(const SeekTable &)... +\n");
+       printf("        SeekTable::operator==(const SeekTable &)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        SeekTable::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy = seektable_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == seektable_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        SeekTable::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::SeekTable blockcopy = &seektable_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == seektable_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing SeekTable::insert_point() x 3... ");
+       if(!block.insert_point(0, seektable_.data.seek_table.points[1]))
+               return die_("returned false");
+       if(!block.insert_point(0, seektable_.data.seek_table.points[1]))
+               return die_("returned false");
+       if(!block.insert_point(1, seektable_.data.seek_table.points[0]))
+               return die_("returned false");
+       printf("OK\n");
+
+       printf("testing SeekTable::is_legal()... ");
+       if(block.is_legal())
+               return die_("returned true");
+       printf("OK\n");
+
+       printf("testing SeekTable::set_point()... ");
+       block.set_point(0, seektable_.data.seek_table.points[0]);
+       printf("OK\n");
+
+       printf("testing SeekTable::delete_point()... ");
+       if(!block.delete_point(0))
+               return die_("returned false");
+       printf("OK\n");
+
+       printf("testing SeekTable::is_legal()... ");
+       if(!block.is_legal())
+               return die_("returned false");
+       printf("OK\n");
+
+       printf("testing SeekTable::get_num_points()... ");
+       if(block.get_num_points() != seektable_.data.seek_table.num_points)
+               return die_("number mismatch");
+       printf("OK\n");
+
+       printf("testing SeekTable::operator!=(const ::FLAC__StreamMetadata &)... ");
+       if(block != seektable_)
+               return die_("data mismatch");
+       printf("OK\n");
+
+       printf("testing SeekTable::get_point()... ");
+       if(
+               block.get_point(1).sample_number != seektable_.data.seek_table.points[1].sample_number ||
+               block.get_point(1).stream_offset != seektable_.data.seek_table.points[1].stream_offset ||
+               block.get_point(1).frame_samples != seektable_.data.seek_table.points[1].frame_samples
+       )
+               return die_("point mismatch");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::SeekTable *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::SeekTable *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing SeekTable::~SeekTable()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_vorbiscomment()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::VorbisComment::Entry\n");
+
+       printf("testing Entry::Entry()... ");
+       {
+               FLAC::Metadata::VorbisComment::Entry entry1;
+               if(!entry1.is_valid())
+                       return die_("!is_valid()");
+               printf("OK\n");
+
+               printf("testing Entry::~Entry()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Entry::Entry(const char *field, unsigned field_length)... ");
+       FLAC::Metadata::VorbisComment::Entry entry2("name2=value2", strlen("name2=value2"));
+       if(!entry2.is_valid())
+               return die_("!is_valid()");
+       printf("OK\n");
+
+       {
+               printf("testing Entry::Entry(const char *field)... ");
+               FLAC::Metadata::VorbisComment::Entry entry2z("name2=value2");
+               if(!entry2z.is_valid())
+                       return die_("!is_valid()");
+               if(strcmp(entry2.get_field(), entry2z.get_field()))
+                       return die_("bad value");
+               printf("OK\n");
+       }
+
+       printf("testing Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)... ");
+       FLAC::Metadata::VorbisComment::Entry entry3("name3", "value3", strlen("value3"));
+       if(!entry3.is_valid())
+               return die_("!is_valid()");
+       printf("OK\n");
+
+       {
+               printf("testing Entry::Entry(const char *field_name, const char *field_value)... ");
+               FLAC::Metadata::VorbisComment::Entry entry3z("name3", "value3");
+               if(!entry3z.is_valid())
+                       return die_("!is_valid()");
+               if(strcmp(entry3.get_field(), entry3z.get_field()))
+                       return die_("bad value");
+               printf("OK\n");
+       }
+
+       printf("testing Entry::Entry(const Entry &entry)... ");
+       {
+               FLAC::Metadata::VorbisComment::Entry entry2copy(entry2);
+               if(!entry2copy.is_valid())
+                       return die_("!is_valid()");
+               printf("OK\n");
+
+               printf("testing Entry::~Entry()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Entry::operator=(const Entry &entry)... ");
+       FLAC::Metadata::VorbisComment::Entry entry1 = entry2;
+       if(!entry2.is_valid())
+               return die_("!is_valid()");
+       printf("OK\n");
+
+       printf("testing Entry::get_field_length()... ");
+       if(entry1.get_field_length() != strlen("name2=value2"))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::get_field_name_length()... ");
+       if(entry1.get_field_name_length() != strlen("name2"))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::get_field_value_length()... ");
+       if(entry1.get_field_value_length() != strlen("value2"))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::get_entry()... ");
+       {
+               ::FLAC__StreamMetadata_VorbisComment_Entry entry = entry1.get_entry();
+               if(entry.length != strlen("name2=value2"))
+                       return die_("entry length mismatch");
+               if(0 != memcmp(entry.entry, "name2=value2", entry.length))
+                       return die_("entry value mismatch");
+       }
+       printf("OK\n");
+
+       printf("testing Entry::get_field()... ");
+       if(0 != memcmp(entry1.get_field(), "name2=value2", strlen("name2=value2")))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::get_field_name()... ");
+       if(0 != memcmp(entry1.get_field_name(), "name2", strlen("name2")))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::get_field_value()... ");
+       if(0 != memcmp(entry1.get_field_value(), "value2", strlen("value2")))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::set_field_name()... ");
+       if(!entry1.set_field_name("name1"))
+               return die_("returned false");
+       if(0 != memcmp(entry1.get_field_name(), "name1", strlen("name1")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field(), "name1=value2", strlen("name1=value2")))
+               return die_("entry mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::set_field_value(const char *field_value, unsigned field_value_length)... ");
+       if(!entry1.set_field_value("value1", strlen("value1")))
+               return die_("returned false");
+       if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1")))
+               return die_("entry mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::set_field_value(const char *field_value)... ");
+       if(!entry1.set_field_value("value1"))
+               return die_("returned false");
+       if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1")))
+               return die_("entry mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::set_field(const char *field, unsigned field_length)... ");
+       if(!entry1.set_field("name0=value0", strlen("name0=value0")))
+               return die_("returned false");
+       if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0")))
+               return die_("entry mismatch");
+       printf("OK\n");
+
+       printf("testing Entry::set_field(const char *field)... ");
+       if(!entry1.set_field("name0=value0"))
+               return die_("returned false");
+       if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0")))
+               return die_("value mismatch");
+       if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0")))
+               return die_("entry mismatch");
+       printf("OK\n");
+
+       printf("PASSED\n\n");
+
+
+       printf("testing class FLAC::Metadata::VorbisComment\n");
+
+       printf("testing VorbisComment::VorbisComment()... ");
+       FLAC::Metadata::VorbisComment block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(::FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8);
+       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 VorbisComment::VorbisComment(const VorbisComment &)... +\n");
+       printf("        VorbisComment::operator!=(const VorbisComment &)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing VorbisComment::~VorbisComment()... ");
+       }
+       printf("OK\n");
+
+       printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy(vorbiscomment_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_);
+               FLAC::Metadata::VorbisComment blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy;
+               blockcopy.assign(&vorbiscomment_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_);
+               FLAC::Metadata::VorbisComment blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != vorbiscomment_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::operator=(const VorbisComment &)... +\n");
+       printf("        VorbisComment::operator==(const VorbisComment &)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        VorbisComment::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy = vorbiscomment_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == vorbiscomment_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        VorbisComment::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::VorbisComment blockcopy = &vorbiscomment_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == vorbiscomment_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing VorbisComment::get_num_comments()... ");
+       if(block.get_num_comments() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing VorbisComment::set_vendor_string()... ");
+       if(!block.set_vendor_string((const FLAC__byte *)"mame0"))
+               return die_("returned false");
+       printf("OK\n");
+       vorbiscomment_.data.vorbis_comment.vendor_string.entry[0] = 'm';
+
+       printf("testing VorbisComment::get_vendor_string()... ");
+       if(strlen((const char *)block.get_vendor_string()) != vorbiscomment_.data.vorbis_comment.vendor_string.length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_vendor_string(), vorbiscomment_.data.vorbis_comment.vendor_string.entry, vorbiscomment_.data.vorbis_comment.vendor_string.length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::append_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.append_comment(entry3))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::append_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.append_comment(entry2))
+               return die_("returned false");
+       if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::delete_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.delete_comment(0))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+               return die_("length[0] mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+               return die_("value[0] mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::delete_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.delete_comment(0))
+               return die_("returned false");
+       if(block.get_num_comments() != 0)
+               return die_("block mismatch, expected num_comments = 0");
+       printf("OK\n");
+
+       printf("testing VorbisComment::insert_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.insert_comment(0, entry3))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::insert_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.insert_comment(0, entry3))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::insert_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.insert_comment(1, entry2))
+               return die_("returned false");
+       if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::set_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.set_comment(0, entry2))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing VorbisComment::delete_comment()... +\n");
+       printf("        VorbisComment::get_comment()... ");
+       if(!block.delete_comment(0))
+               return die_("returned false");
+       if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+               return die_("length[0] mismatch");
+       if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+               return die_("value[0] mismatch");
+       if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+               return die_("length[1] mismatch");
+       if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+               return die_("value[0] mismatch");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::VorbisComment *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::VorbisComment *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing VorbisComment::~VorbisComment()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_cuesheet()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::CueSheet::Track\n");
+
+       printf("testing Track::Track()... ");
+       FLAC::Metadata::CueSheet::Track track0;
+       if(!track0.is_valid())
+               return die_("!is_valid()");
+       printf("OK\n");
+
+       {
+               printf("testing Track::get_track()... ");
+               const ::FLAC__StreamMetadata_CueSheet_Track *trackp = track0.get_track();
+               if(0 == trackp)
+                       return die_("returned pointer is NULL");
+               printf("OK\n");
+
+               printf("testing Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track*)... ");
+               FLAC::Metadata::CueSheet::Track track2(trackp);
+               if(!track2.is_valid())
+                       return die_("!is_valid()");
+               if(!track_is_equal_(track2.get_track(), trackp))
+                       return die_("copy is not equal");
+               printf("OK\n");
+
+               printf("testing Track::~Track()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Track::Track(const Track &track)... ");
+       {
+               FLAC::Metadata::CueSheet::Track track0copy(track0);
+               if(!track0copy.is_valid())
+                       return die_("!is_valid()");
+               if(!track_is_equal_(track0copy.get_track(), track0.get_track()))
+                       return die_("copy is not equal");
+               printf("OK\n");
+
+               printf("testing Track::~Track()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Track::operator=(const Track &track)... ");
+       FLAC::Metadata::CueSheet::Track track1 = track0;
+       if(!track0.is_valid())
+               return die_("!is_valid()");
+       if(!track_is_equal_(track1.get_track(), track0.get_track()))
+               return die_("copy is not equal");
+       printf("OK\n");
+
+       printf("testing Track::get_offset()... ");
+       if(track1.get_offset() != 0)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::get_number()... ");
+       if(track1.get_number() != 0)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::get_isrc()... ");
+       if(0 != memcmp(track1.get_isrc(), "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::get_type()... ");
+       if(track1.get_type() != 0)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::get_pre_emphasis()... ");
+       if(track1.get_pre_emphasis() != 0)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::get_num_indices()... ");
+       if(track1.get_num_indices() != 0)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::set_offset()... ");
+       track1.set_offset(588);
+       if(track1.get_offset() != 588)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::set_number()... ");
+       track1.set_number(1);
+       if(track1.get_number() != 1)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::set_isrc()... ");
+       track1.set_isrc("ABCDE1234567");
+       if(0 != memcmp(track1.get_isrc(), "ABCDE1234567", 13))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::set_type()... ");
+       track1.set_type(1);
+       if(track1.get_type() != 1)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Track::set_pre_emphasis()... ");
+       track1.set_pre_emphasis(1);
+       if(track1.get_pre_emphasis() != 1)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("PASSED\n\n");
+
+       printf("testing class FLAC::Metadata::CueSheet\n");
+
+       printf("testing CueSheet::CueSheet()... ");
+       FLAC::Metadata::CueSheet block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = (
+               FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+       ) / 8;
+       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 CueSheet::CueSheet(const CueSheet &)... +\n");
+       printf("        CueSheet::operator!=(const CueSheet &)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing CueSheet::~CueSheet()... ");
+       }
+       printf("OK\n");
+
+       printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy(cuesheet_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy(&cuesheet_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy(&cuesheet_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_);
+               FLAC::Metadata::CueSheet blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy;
+               blockcopy.assign(&cuesheet_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        CueSheet::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_);
+               FLAC::Metadata::CueSheet blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != cuesheet_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::operator=(const CueSheet &)... +\n");
+       printf("        CueSheet::operator==(const CueSheet &)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        CueSheet::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy = cuesheet_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == cuesheet_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        CueSheet::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::CueSheet blockcopy = &cuesheet_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == cuesheet_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing CueSheet::get_media_catalog_number()... ");
+       if(0 != strcmp(block.get_media_catalog_number(), ""))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::get_lead_in()... ");
+       if(block.get_lead_in() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing CueSheet::get_is_cd()... ");
+       if(block.get_is_cd())
+               return die_("value mismatch, expected false");
+       printf("OK\n");
+
+       printf("testing CueSheet::get_num_tracks()... ");
+       if(block.get_num_tracks() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing CueSheet::set_media_catalog_number()... ");
+       {
+               char mcn[129];
+               memset(mcn, 0, sizeof(mcn));
+               strcpy(mcn, "1234567890123");
+               block.set_media_catalog_number(mcn);
+               if(0 != memcmp(block.get_media_catalog_number(), mcn, sizeof(mcn)))
+                       return die_("value mismatch");
+       }
+       printf("OK\n");
+
+       printf("testing CueSheet::set_lead_in()... ");
+       block.set_lead_in(588);
+       if(block.get_lead_in() != 588)
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::set_is_cd()... ");
+       block.set_is_cd(true);
+       if(!block.get_is_cd())
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::insert_track()... +\n");
+       printf("        CueSheet::get_track()... ");
+       if(!block.insert_track(0, track0))
+               return die_("returned false");
+       if(!track_is_equal_(block.get_track(0).get_track(), track0.get_track()))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::insert_track()... +\n");
+       printf("        CueSheet::get_track()... ");
+       if(!block.insert_track(1, track1))
+               return die_("returned false");
+       if(!track_is_equal_(block.get_track(1).get_track(), track1.get_track()))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       ::FLAC__StreamMetadata_CueSheet_Index index0;
+       index0.offset = 588*4;
+       index0.number = 1;
+
+       printf("testing CueSheet::insert_index(0)... +\n");
+       printf("        CueSheet::get_track()... +\n");
+       printf("        CueSheet::Track::get_index()... ");
+       if(!block.insert_index(0, 0, index0))
+               return die_("returned false");
+       if(!index_is_equal_(block.get_track(0).get_index(0), index0))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       index0.offset = 588*5;
+       printf("testing CueSheet::Track::set_index()... ");
+       {
+               FLAC::Metadata::CueSheet::Track track_ = block.get_track(0);
+               track_.set_index(0, index0);
+               if(!index_is_equal_(track_.get_index(0), index0))
+                       return die_("value mismatch");
+       }
+       printf("OK\n");
+
+       index0.offset = 588*6;
+       printf("testing CueSheet::set_index()... ");
+       block.set_index(0, 0, index0);
+       if(!index_is_equal_(block.get_track(0).get_index(0), index0))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::delete_index()... ");
+       if(!block.delete_index(0, 0))
+               return die_("returned false");
+       if(block.get_track(0).get_num_indices() != 0)
+               return die_("num_indices mismatch");
+       printf("OK\n");
+
+
+       printf("testing CueSheet::set_track()... +\n");
+       printf("        CueSheet::get_track()... ");
+       if(!block.set_track(0, track1))
+               return die_("returned false");
+       if(!track_is_equal_(block.get_track(0).get_track(), track1.get_track()))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing CueSheet::delete_track()... ");
+       if(!block.delete_track(0))
+               return die_("returned false");
+       if(block.get_num_tracks() != 1)
+               return die_("num_tracks mismatch");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::CueSheet *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::CueSheet *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing CueSheet::~CueSheet()... ");
+       delete clone_;
+       printf("OK\n");
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object_picture()
+{
+       unsigned expected_length;
+
+       printf("testing class FLAC::Metadata::Picture\n");
+
+       printf("testing Picture::Picture()... ");
+       FLAC::Metadata::Picture block;
+       if(!block.is_valid())
+               return die_("!block.is_valid()");
+       expected_length = (
+               FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+               FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN
+       ) / 8;
+       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 Picture::Picture(const Picture &)... +\n");
+       printf("        Picture::operator!=(const Picture &)... ");
+       {
+               FLAC::Metadata::Picture blockcopy(block);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != block)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+
+               printf("testing Picture::~Picture()... ");
+       }
+       printf("OK\n");
+
+       printf("testing Picture::Picture(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Picture blockcopy(picture_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::Picture(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Picture blockcopy(&picture_);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Picture blockcopy(&picture_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+               FLAC::Metadata::Picture blockcopy(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Picture blockcopy;
+               blockcopy.assign(&picture_, /*copy=*/true);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+       printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+       {
+               ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+               FLAC::Metadata::Picture blockcopy;
+               blockcopy.assign(copy, /*copy=*/false);
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(blockcopy != picture_)
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::operator=(const Picture &)... +\n");
+       printf("        Picture::operator==(const Picture &)... ");
+       {
+               FLAC::Metadata::Picture blockcopy = block;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == block))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::operator=(const ::FLAC__StreamMetadata &)... +\n");
+       printf("        Picture::operator==(const ::FLAC__StreamMetadata &)... ");
+       {
+               FLAC::Metadata::Picture blockcopy = picture_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == picture_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::operator=(const ::FLAC__StreamMetadata *)... +\n");
+       printf("        Picture::operator==(const ::FLAC__StreamMetadata *)... ");
+       {
+               FLAC::Metadata::Picture blockcopy = &picture_;
+               if(!blockcopy.is_valid())
+                       return die_("!blockcopy.is_valid()");
+               if(!(blockcopy == picture_))
+                       return die_("copy is not identical to original");
+               printf("OK\n");
+       }
+
+       printf("testing Picture::get_type()... ");
+       if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER)
+               return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER");
+       printf("OK\n");
+
+       printf("testing Picture::set_type()... +\n");
+       printf("        Picture::get_type()... ");
+       block.set_type(::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA);
+       if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA)
+               return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA");
+       printf("OK\n");
+
+       printf("testing Picture::set_mime_type()... ");
+       if(!block.set_mime_type("qmage/jpeg"))
+               return die_("returned false");
+       printf("OK\n");
+       picture_.data.picture.mime_type[0] = 'q';
+
+       printf("testing Picture::get_mime_type()... ");
+       if(0 != strcmp(block.get_mime_type(), picture_.data.picture.mime_type))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Picture::set_description()... ");
+       if(!block.set_description((const FLAC__byte*)"qesc"))
+               return die_("returned false");
+       printf("OK\n");
+       picture_.data.picture.description[0] = 'q';
+
+       printf("testing Picture::get_description()... ");
+       if(0 != strcmp((const char *)block.get_description(), (const char *)picture_.data.picture.description))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing Picture::get_width()... ");
+       if(block.get_width() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing Picture::set_width()... +\n");
+       printf("        Picture::get_width()... ");
+       block.set_width(400);
+       if(block.get_width() != 400)
+               return die_("value mismatch, expected 400");
+       printf("OK\n");
+
+       printf("testing Picture::get_height()... ");
+       if(block.get_height() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing Picture::set_height()... +\n");
+       printf("        Picture::get_height()... ");
+       block.set_height(200);
+       if(block.get_height() != 200)
+               return die_("value mismatch, expected 200");
+       printf("OK\n");
+
+       printf("testing Picture::get_depth()... ");
+       if(block.get_depth() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing Picture::set_depth()... +\n");
+       printf("        Picture::get_depth()... ");
+       block.set_depth(16);
+       if(block.get_depth() != 16)
+               return die_("value mismatch, expected 16");
+       printf("OK\n");
+
+       printf("testing Picture::get_colors()... ");
+       if(block.get_colors() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing Picture::set_colors()... +\n");
+       printf("        Picture::get_colors()... ");
+       block.set_colors(1u>16);
+       if(block.get_colors() != 1u>16)
+               return die_("value mismatch, expected 2^16");
+       printf("OK\n");
+
+       printf("testing Picture::get_data_length()... ");
+       if(block.get_data_length() != 0)
+               return die_("value mismatch, expected 0");
+       printf("OK\n");
+
+       printf("testing Picture::set_data()... ");
+       if(!block.set_data((const FLAC__byte*)"qOMEJPEGDATA", strlen("qOMEJPEGDATA")))
+               return die_("returned false");
+       printf("OK\n");
+       picture_.data.picture.data[0] = 'q';
+
+       printf("testing Picture::get_data()... ");
+       if(block.get_data_length() != picture_.data.picture.data_length)
+               return die_("length mismatch");
+       if(0 != memcmp(block.get_data(), picture_.data.picture.data, picture_.data.picture.data_length))
+               return die_("value mismatch");
+       printf("OK\n");
+
+       printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+       FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+       if(0 == clone_)
+               return die_("returned NULL");
+       if(0 == dynamic_cast<FLAC::Metadata::Picture *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::Picture *>(clone_) != block)
+               return die_("clone is not identical");
+       printf("OK\n");
+       printf("testing Picture::~Picture()... ");
+       delete clone_;
+       printf("OK\n");
+
+
+       printf("PASSED\n\n");
+       return true;
+}
+
+bool test_metadata_object()
+{
+       printf("\n+++ libFLAC++ unit test: metadata objects\n\n");
+
+       init_metadata_blocks_();
+
+       if(!test_metadata_object_streaminfo())
+               return false;
+
+       if(!test_metadata_object_padding())
+               return false;
+
+       if(!test_metadata_object_application())
+               return false;
+
+       if(!test_metadata_object_seektable())
+               return false;
+
+       if(!test_metadata_object_vorbiscomment())
+               return false;
+
+       if(!test_metadata_object_cuesheet())
+               return false;
+
+       if(!test_metadata_object_picture())
+               return false;
+
+       free_metadata_blocks_();
+
+       return true;
+}
diff --git a/src/test_libFLAC++/test_libFLAC++.dsp b/src/test_libFLAC++/test_libFLAC++.dsp
new file mode 100644 (file)
index 0000000..edb8942
--- /dev/null
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="test_libFLAC++" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_libFLAC++ - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libFLAC++.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libFLAC++.mak" CFG="test_libFLAC++ - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_libFLAC++ - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_libFLAC++ - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_libFLAC++ - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\obj\release\lib\test_libs_common_static.lib ..\..\obj\release\lib\libFLAC++_static.lib ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_libFLAC++ - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\grabbag_static.lib ..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\obj\debug\lib\test_libs_common_static.lib ..\..\obj\debug\lib\libFLAC++_static.lib ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_libFLAC++ - Win32 Release"\r
+# Name "test_libFLAC++ - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\decoders.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encoders.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\main.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_manip.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_object.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\decoders.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encoders.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\README\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/src/test_libFLAC++/test_libFLAC++.vcproj b/src/test_libFLAC++/test_libFLAC++.vcproj
new file mode 100644 (file)
index 0000000..50cfdcc
--- /dev/null
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_libFLAC++"\r
+       ProjectGUID="{4cefbc8d-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_libFLAC++"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\decoders.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encoders.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\decoders.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encoders.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\main.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_manip.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_object.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_libFLAC/Makefile.am b/src/test_libFLAC/Makefile.am
new file mode 100644 (file)
index 0000000..d38f299
--- /dev/null
@@ -0,0 +1,47 @@
+#  test_libFLAC - Unit tester for libFLAC
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_libFLAC.dsp \
+       test_libFLAC.vcproj
+
+INCLUDES = -I$(top_srcdir)/src/libFLAC/include
+
+noinst_PROGRAMS = test_libFLAC
+test_libFLAC_LDADD = \
+       $(top_builddir)/src/share/grabbag/libgrabbag.la \
+       $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+       $(top_builddir)/src/test_libs_common/libtest_libs_common.la \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+test_libFLAC_SOURCES = \
+       bitwriter.c \
+       decoders.c \
+       encoders.c \
+       format.c \
+       main.c \
+       metadata.c \
+       metadata_manip.c \
+       metadata_object.c \
+       bitwriter.h \
+       decoders.h \
+       encoders.h \
+       format.h \
+       metadata.h
diff --git a/src/test_libFLAC/Makefile.lite b/src/test_libFLAC/Makefile.lite
new file mode 100644 (file)
index 0000000..60d9920
--- /dev/null
@@ -0,0 +1,47 @@
+#  test_libFLAC - Unit tester for libFLAC
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_libFLAC
+
+INCLUDES = -I../libFLAC/include -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libreplaygain_analysis.a $(libdir)/libtest_libs_common.a $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lgrabbag -lreplaygain_analysis -ltest_libs_common -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       bitwriter.c \
+       decoders.c \
+       encoders.c \
+       format.c \
+       main.c \
+       metadata.c \
+       metadata_manip.c \
+       metadata_object.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libFLAC/bitwriter.c b/src/test_libFLAC/bitwriter.c
new file mode 100644 (file)
index 0000000..7bc23a8
--- /dev/null
@@ -0,0 +1,584 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "private/bitwriter.h" /* from the libFLAC private include area */
+#include "bitwriter.h"
+#include <stdio.h>
+#include <string.h> /* for memcmp() */
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/*
+ * WATCHOUT!  Since FLAC__BitWriter is a private structure, we use a copy of
+ * the definition here to get at the internals.  Make sure this is kept up
+ * to date with what is in ../libFLAC/bitwriter.c
+ */
+typedef FLAC__uint32 bwword;
+
+struct FLAC__BitWriter {
+       bwword *buffer;
+       bwword accum; /* accumulator; when full, accum is appended to buffer */
+       unsigned capacity; /* of buffer in words */
+       unsigned words; /* # of complete words in buffer */
+       unsigned bits; /* # of used bits in accum */
+};
+
+#define TOTAL_BITS(bw) ((bw)->words*sizeof(bwword)*8 + (bw)->bits)
+
+
+FLAC__bool test_bitwriter(void)
+{
+       FLAC__BitWriter *bw;
+       FLAC__bool ok;
+       unsigned i, j;
+#if WORDS_BIGENDIAN
+       static bwword test_pattern1[5] = { 0xaaf0aabe, 0xaaaaaaa8, 0x300aaaaa, 0xaaadeadb, 0x00eeface };
+#else
+       static bwword test_pattern1[5] = { 0xbeaaf0aa, 0xa8aaaaaa, 0xaaaa0a30, 0xdbeaadaa, 0x00eeface };
+#endif
+       unsigned words, bits; /* what we think bw->words and bw->bits should be */
+
+       printf("\n+++ libFLAC unit test: bitwriter\n\n");
+
+       /*
+        * test new -> delete
+        */
+       printf("testing new... ");
+       bw = FLAC__bitwriter_new();
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing delete... ");
+       FLAC__bitwriter_delete(bw);
+       printf("OK\n");
+
+       /*
+        * test new -> init -> delete
+        */
+       printf("testing new... ");
+       bw = FLAC__bitwriter_new();
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing init... ");
+       FLAC__bitwriter_init(bw);
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing delete... ");
+       FLAC__bitwriter_delete(bw);
+       printf("OK\n");
+
+       /*
+        * test new -> init -> clear -> delete
+        */
+       printf("testing new... ");
+       bw = FLAC__bitwriter_new();
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing init... ");
+       FLAC__bitwriter_init(bw);
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing clear... ");
+       FLAC__bitwriter_clear(bw);
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing delete... ");
+       FLAC__bitwriter_delete(bw);
+       printf("OK\n");
+
+       /*
+        * test normal usage
+        */
+       printf("testing new... ");
+       bw = FLAC__bitwriter_new();
+       if(0 == bw) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing init... ");
+       ok = FLAC__bitwriter_init(bw);
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok)
+               return false;
+
+       printf("testing clear... ");
+       FLAC__bitwriter_clear(bw);
+       printf("OK\n");
+
+       words = bits = 0;
+
+       printf("capacity = %u\n", bw->capacity);
+
+       printf("testing zeroes, raw_uint32*... ");
+       ok =
+               FLAC__bitwriter_write_raw_uint32(bw, 0x1, 1) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0x1, 2) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0xa, 5) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0xf0, 8) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0x2aa, 10) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0xf, 4) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32) &&
+               FLAC__bitwriter_write_zeroes(bw, 4) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0x3, 2) &&
+               FLAC__bitwriter_write_zeroes(bw, 8) &&
+               FLAC__bitwriter_write_raw_uint64(bw, FLAC__U64L(0xaaaaaaaadeadbeef), 64) &&
+               FLAC__bitwriter_write_raw_uint32(bw, 0xace, 12)
+       ;
+       if(!ok) {
+               printf("FAILED\n");
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       words = 4;
+       bits = 24;
+       if(bw->words != words) {
+               printf("FAILED byte count %u != %u\n", bw->words, words);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if(bw->bits != bits) {
+               printf("FAILED bit count %u != %u\n", bw->bits, bits);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+               printf("FAILED pattern match (buffer)\n");
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if((bw->accum & 0x00ffffff) != test_pattern1[words]) {
+               printf("FAILED pattern match (bw->accum=%08X != %08X)\n", bw->accum&0x00ffffff, test_pattern1[words]);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       printf("OK\n");
+       FLAC__bitwriter_dump(bw, stdout);
+
+       printf("testing raw_uint32 some more... ");
+       ok = FLAC__bitwriter_write_raw_uint32(bw, 0x3d, 6);
+       if(!ok) {
+               printf("FAILED\n");
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       bits += 6;
+       test_pattern1[words] <<= 6;
+       test_pattern1[words] |= 0x3d;
+       if(bw->words != words) {
+               printf("FAILED byte count %u != %u\n", bw->words, words);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if(bw->bits != bits) {
+               printf("FAILED bit count %u != %u\n", bw->bits, bits);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+               printf("FAILED pattern match (buffer)\n");
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       if((bw->accum & 0x3fffffff) != test_pattern1[words]) {
+               printf("FAILED pattern match (bw->accum=%08X != %08X)\n", bw->accum&0x3fffffff, test_pattern1[words]);
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       printf("OK\n");
+       FLAC__bitwriter_dump(bw, stdout);
+
+       printf("testing utf8_uint32(0x00000000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x00000000);
+       ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x0000007F)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x0000007F);
+       ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x00000080)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x00000080);
+       ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x000007FF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x000007FF);
+       ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x00000800)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x00000800);
+       ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x0000FFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x0000FFFF);
+       ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x00010000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x00010000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x001FFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x001FFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x00200000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x00200000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x03FFFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x03FFFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x04000000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x04000000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint32(0x7FFFFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint32(bw, 0x7FFFFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000000000000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000000);
+       ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x000000000000007F)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x000000000000007F);
+       ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000000000080)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000080);
+       ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x00000000000007FF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x00000000000007FF);
+       ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000000000800)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000800);
+       ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x000000000000FFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x000000000000FFFF);
+       ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000000010000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000010000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x00000000001FFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x00000000001FFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+       ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000000200000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000200000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000003FFFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000003FFFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+       ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000004000000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000004000000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x000000007FFFFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x000000007FFFFFFF);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+       ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000080000000)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000080000000);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFE828080 && (bw->accum & 0xffffff) == 0x808080;
+#else
+       ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0x808082FE && (bw->accum & 0xffffff) == 0x808080;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing utf8_uint64(0x0000000FFFFFFFFF)... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000FFFFFFFFF));
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFEBFBFBF && (bw->accum & 0xffffff) == 0xBFBFBF;
+#else
+       ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xBFBFBFFE && (bw->accum & 0xffffff) == 0xBFBFBF;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+
+       printf("testing grow... ");
+       FLAC__bitwriter_clear(bw);
+       FLAC__bitwriter_write_raw_uint32(bw, 0x5, 4);
+       j = bw->capacity;
+       for(i = 0; i < j; i++)
+               FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32);
+#if WORDS_BIGENDIAN
+       ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0x5aaaaaaa && (bw->accum & 0xf) == 0xa;
+#else
+       ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0xaaaaaa5a && (bw->accum & 0xf) == 0xa;
+#endif
+       printf("%s\n", ok?"OK":"FAILED");
+       if(!ok) {
+               FLAC__bitwriter_dump(bw, stdout);
+               return false;
+       }
+       printf("capacity = %u\n", bw->capacity);
+
+       printf("testing free... ");
+       FLAC__bitwriter_free(bw);
+       printf("OK\n");
+
+       printf("testing delete... ");
+       FLAC__bitwriter_delete(bw);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+       return true;
+}
diff --git a/src/test_libFLAC/bitwriter.h b/src/test_libFLAC/bitwriter.h
new file mode 100644 (file)
index 0000000..44b6ade
--- /dev/null
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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_BITBUFFER_H
+#define FLAC__TEST_LIBFLAC_BITBUFFER_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_bitwriter(void);
+
+#endif
diff --git a/src/test_libFLAC/decoders.c b/src/test_libFLAC/decoders.c
new file mode 100644 (file)
index 0000000..1d731cd
--- /dev/null
@@ -0,0 +1,1048 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+       LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */
+       LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */
+       LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */
+       LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+       "Stream",
+       "Seekable Stream",
+       "FILE*",
+       "Filename"
+};
+
+typedef struct {
+       Layer layer;
+       FILE *file;
+       unsigned current_metadata_number;
+       FLAC__bool ignore_errors;
+       FLAC__bool error_occurred;
+} StreamDecoderClientData;
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static unsigned num_expected_;
+static off_t flacfilesize_;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+       FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamDecoderStateString[state]);
+
+       return false;
+}
+
+static void init_metadata_blocks_(void)
+{
+       mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+       mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__bool generate_file_(FLAC__bool is_ogg)
+{
+       printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &picture_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+       /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+       if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+               return die_("creating the encoded file");
+
+       return true;
+}
+
+static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+       const size_t requested_bytes = *bytes;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in read callback is NULL\n");
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+       if(feof(dcd->file)) {
+               *bytes = 0;
+               return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+       }
+       else if(requested_bytes > 0) {
+               *bytes = fread(buffer, 1, requested_bytes, dcd->file);
+               if(*bytes == 0) {
+                       if(feof(dcd->file))
+                               return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+                       else
+                               return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+               }
+               else {
+                       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+               }
+       }
+       else
+               return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in seek callback is NULL\n");
+               return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+       if(fseeko(dcd->file, (off_t)absolute_byte_offset, SEEK_SET) < 0) {
+               dcd->error_occurred = true;
+               return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+       }
+
+       return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+       off_t offset;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in tell callback is NULL\n");
+               return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+       offset = ftello(dcd->file);
+       *absolute_byte_offset = (FLAC__uint64)offset;
+
+       if(offset < 0) {
+               dcd->error_occurred = true;
+               return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+       }
+
+       return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in length callback is NULL\n");
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+       *stream_length = (FLAC__uint64)flacfilesize_;
+       return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in eof callback is NULL\n");
+               return true;
+       }
+
+       if(dcd->error_occurred)
+               return true;
+
+       return feof(dcd->file);
+}
+
+static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder, (void)buffer;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in write callback is NULL\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+       if(
+               (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+               (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+       ) {
+               printf("content... ");
+               fflush(stdout);
+       }
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in metadata callback is NULL\n");
+               return;
+       }
+
+       if(dcd->error_occurred)
+               return;
+
+       printf("%d... ", dcd->current_metadata_number);
+       fflush(stdout);
+
+       if(dcd->current_metadata_number >= num_expected_) {
+               (void)die_("got more metadata blocks than expected");
+               dcd->error_occurred = true;
+       }
+       else {
+               if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
+                       (void)die_("metadata block mismatch");
+                       dcd->error_occurred = true;
+               }
+       }
+       dcd->current_metadata_number++;
+}
+
+static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in error callback is NULL\n");
+               return;
+       }
+
+       if(!dcd->ignore_errors) {
+               printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
+               dcd->error_occurred = true;
+       }
+}
+
+static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg)
+{
+       FLAC__StreamDecoderInitStatus init_status;
+
+       if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+               return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder);
+
+       /* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */
+       if(dcd->layer == LAYER_FILE) {
+               printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+               dcd->file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == dcd->file) {
+                       printf("ERROR (%s)\n", strerror(errno));
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       switch(dcd->layer) {
+               case LAYER_STREAM:
+                       printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+                               FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd)
+                       ;
+                       break;
+               case LAYER_SEEKABLE_STREAM:
+                       printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+                               FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+                       break;
+               case LAYER_FILE:
+                       printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+                               FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+                               FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+                       break;
+               default:
+                       die_("internal error 000");
+                       return false;
+       }
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, decoder);
+       printf("OK\n");
+
+       dcd->current_metadata_number = 0;
+
+       if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) {
+               printf("FAILED rewinding input, errno = %d\n", errno);
+               return false;
+       }
+
+       printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+       if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_finish()... ");
+       if(!FLAC__stream_decoder_finish(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       return true;
+}
+
+static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
+{
+       FLAC__StreamDecoder *decoder;
+       FLAC__StreamDecoderInitStatus init_status;
+       FLAC__StreamDecoderState state;
+       StreamDecoderClientData decoder_client_data;
+       FLAC__bool expect;
+
+       decoder_client_data.layer = layer;
+
+       printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+       printf("testing FLAC__stream_decoder_new()... ");
+       decoder = FLAC__stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_delete()... ");
+       FLAC__stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_new()... ");
+       decoder = FLAC__stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       switch(layer) {
+               case LAYER_STREAM:
+               case LAYER_SEEKABLE_STREAM:
+                       printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) :
+                               FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                       break;
+               case LAYER_FILE:
+                       printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) :
+                               FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0);
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) :
+                               FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0);
+                       break;
+               default:
+                       die_("internal error 003");
+                       return false;
+       }
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS)
+               return die_s_(0, decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_delete()... ");
+       FLAC__stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+       printf("testing FLAC__stream_decoder_new()... ");
+       decoder = FLAC__stream_decoder_new();
+       if(0 == decoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       if(is_ogg) {
+               printf("testing FLAC__stream_decoder_set_ogg_serial_number()... ");
+               if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number))
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+       }
+
+       printf("testing FLAC__stream_decoder_set_md5_checking()... ");
+       if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILENAME) {
+               printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+               decoder_client_data.file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == decoder_client_data.file) {
+                       printf("ERROR (%s)\n", strerror(errno));
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       switch(layer) {
+               case LAYER_STREAM:
+                       printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+                               FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+                       break;
+               case LAYER_SEEKABLE_STREAM:
+                       printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+                               FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+                       break;
+               case LAYER_FILE:
+                       printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+                               FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+                               FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+                       break;
+               default:
+                       die_("internal error 009");
+                       return false;
+       }
+       if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return die_s_(0, decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_get_state()... ");
+       state = FLAC__stream_decoder_get_state(decoder);
+       printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
+
+       decoder_client_data.current_metadata_number = 0;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("testing FLAC__stream_decoder_get_md5_checking()... ");
+       if(!FLAC__stream_decoder_get_md5_checking(decoder)) {
+               printf("FAILED, returned false, expected true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... ");
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_process_single()... ");
+       if(!FLAC__stream_decoder_process_single(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_skip_single_frame()... ");
+       if(!FLAC__stream_decoder_skip_single_frame(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILE) {
+               printf("testing FLAC__stream_decoder_flush()... ");
+               if(!FLAC__stream_decoder_flush(decoder))
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+
+               decoder_client_data.ignore_errors = true;
+               printf("testing FLAC__stream_decoder_process_single()... ");
+               if(!FLAC__stream_decoder_process_single(decoder))
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+               decoder_client_data.ignore_errors = false;
+       }
+
+       expect = (layer != LAYER_STREAM);
+       printf("testing FLAC__stream_decoder_seek_absolute()... ");
+       if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+               return die_s_(expect? "returned false" : "returned true", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+       if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       expect = (layer != LAYER_STREAM);
+       printf("testing FLAC__stream_decoder_seek_absolute()... ");
+       if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+               return die_s_(expect? "returned false" : "returned true", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_get_channels()... ");
+       {
+               unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+               if(channels != streaminfo_.data.stream_info.channels) {
+                       printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels);
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_get_bits_per_sample()... ");
+       {
+               unsigned bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder);
+               if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) {
+                       printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample);
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_get_sample_rate()... ");
+       {
+               unsigned sample_rate = FLAC__stream_decoder_get_sample_rate(decoder);
+               if(sample_rate != streaminfo_.data.stream_info.sample_rate) {
+                       printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate);
+                       return false;
+               }
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_get_blocksize()... ");
+       {
+               unsigned blocksize = FLAC__stream_decoder_get_blocksize(decoder);
+               /* value could be anything since we're at the last block, so accept any reasonable answer */
+               printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+               if(blocksize == 0)
+                       return false;
+       }
+
+       printf("testing FLAC__stream_decoder_get_channel_assignment()... ");
+       {
+               FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder);
+               printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+       }
+
+       if(layer < LAYER_FILE) {
+               printf("testing FLAC__stream_decoder_reset()... ");
+               if(!FLAC__stream_decoder_reset(decoder)) {
+                       state = FLAC__stream_decoder_get_state(decoder);
+                       printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]);
+                       return false;
+               }
+               printf("OK\n");
+
+               if(layer == LAYER_STREAM) {
+                       /* after a reset() we have to rewind the input ourselves */
+                       printf("rewinding input... ");
+                       if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) {
+                               printf("FAILED, errno = %d\n", errno);
+                               return false;
+                       }
+                       printf("OK\n");
+               }
+
+               decoder_client_data.current_metadata_number = 0;
+
+               printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+               if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+                       return die_s_("returned false", decoder);
+               printf("OK\n");
+       }
+
+       printf("testing FLAC__stream_decoder_finish()... ");
+       if(!FLAC__stream_decoder_finish(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       /*
+        * respond all
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * respond all, ignore VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+       expected_metadata_sequence_[num_expected_++] = &padding_;
+       expected_metadata_sequence_[num_expected_++] = &seektable_;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+       expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+       expected_metadata_sequence_[num_expected_++] = &picture_;
+       expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application2_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all, respond VORBIS_COMMENT
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION id of app#1 & app#2
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application1_;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+       else {
+               expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+               expected_metadata_sequence_[num_expected_++] = &padding_;
+               expected_metadata_sequence_[num_expected_++] = &seektable_;
+               expected_metadata_sequence_[num_expected_++] = &application1_;
+               expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+               expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+               expected_metadata_sequence_[num_expected_++] = &picture_;
+               expected_metadata_sequence_[num_expected_++] = &unknown_;
+       }
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       /*
+        * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+        */
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+       if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+       if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
+       num_expected_ = 0;
+       expected_metadata_sequence_[num_expected_++] = &application2_;
+
+       if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+               return false;
+
+       if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+               fclose(decoder_client_data.file);
+
+       printf("testing FLAC__stream_decoder_delete()... ");
+       FLAC__stream_decoder_delete(decoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+FLAC__bool test_decoders(void)
+{
+       FLAC__bool is_ogg = false;
+
+       while(1) {
+               init_metadata_blocks_();
+
+               if(!generate_file_(is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_FILE, is_ogg))
+                       return false;
+
+               if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+                       return false;
+
+               (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+               free_metadata_blocks_();
+
+               if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+                       break;
+               is_ogg = true;
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC/decoders.h b/src/test_libFLAC/decoders.h
new file mode 100644 (file)
index 0000000..11df106
--- /dev/null
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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_DECODERS_H
+#define FLAC__TEST_LIBFLAC_DECODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_decoders(void);
+
+#endif
diff --git a/src/test_libFLAC/encoders.c b/src/test_libFLAC/encoders.c
new file mode 100644 (file)
index 0000000..5927cb8
--- /dev/null
@@ -0,0 +1,521 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "encoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+       LAYER_STREAM = 0, /* FLAC__stream_encoder_init_[ogg_]stream() without seeking */
+       LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_[ogg_]stream() with seeking */
+       LAYER_FILE, /* FLAC__stream_encoder_init_[ogg_]FILE() */
+       LAYER_FILENAME /* FLAC__stream_encoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+       "Stream",
+       "Seekable Stream",
+       "FILE*",
+       "Filename"
+};
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
+static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamEncoder *encoder)
+{
+       FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(encoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamEncoderStateString[state]);
+       if(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+               FLAC__StreamDecoderState dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+               printf("      verify decoder state = %u (%s)\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+       }
+
+       return false;
+}
+
+static void init_metadata_blocks_(void)
+{
+       mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+       mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       FILE *f = (FILE*)client_data;
+       (void)encoder;
+       if(*bytes > 0) {
+               *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, f);
+               if(ferror(f))
+                       return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+               else if(*bytes == 0)
+                       return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+               else
+                       return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+       }
+       else
+               return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+       FILE *f = (FILE*)client_data;
+       (void)encoder, (void)samples, (void)current_frame;
+       if(fwrite(buffer, 1, bytes, f) != bytes)
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__StreamEncoderSeekStatus stream_encoder_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+       FILE *f = (FILE*)client_data;
+       (void)encoder;
+       if(fseek(f, (long)absolute_byte_offset, SEEK_SET) < 0)
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamEncoderTellStatus stream_encoder_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       FILE *f = (FILE*)client_data;
+       long pos;
+       (void)encoder;
+       if((pos = ftell(f)) < 0)
+               return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+       else {
+               *absolute_byte_offset = (FLAC__uint64)pos;
+               return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+       }
+}
+
+static void stream_encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       (void)encoder, (void)metadata, (void)client_data;
+}
+
+static void stream_encoder_progress_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+       (void)encoder, (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate, (void)client_data;
+}
+
+static FLAC__bool test_stream_encoder(Layer layer, FLAC__bool is_ogg)
+{
+       FLAC__StreamEncoder *encoder;
+       FLAC__StreamEncoderInitStatus init_status;
+       FLAC__StreamEncoderState state;
+       FLAC__StreamDecoderState dstate;
+       FILE *file = 0;
+       FLAC__int32 samples[1024];
+       FLAC__int32 *samples_array[1];
+       unsigned i;
+
+       samples_array[0] = samples;
+
+       printf("\n+++ libFLAC unit test: FLAC__StreamEncoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
+
+       printf("testing FLAC__stream_encoder_new()... ");
+       encoder = FLAC__stream_encoder_new();
+       if(0 == encoder) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       if(is_ogg) {
+               printf("testing FLAC__stream_encoder_set_ogg_serial_number()... ");
+               if(!FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number))
+                       return die_s_("returned false", encoder);
+               printf("OK\n");
+       }
+
+       printf("testing FLAC__stream_encoder_set_verify()... ");
+       if(!FLAC__stream_encoder_set_verify(encoder, true))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_streamable_subset()... ");
+       if(!FLAC__stream_encoder_set_streamable_subset(encoder, true))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_channels()... ");
+       if(!FLAC__stream_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_bits_per_sample()... ");
+       if(!FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_sample_rate()... ");
+       if(!FLAC__stream_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_compression_level()... ");
+       if(!FLAC__stream_encoder_set_compression_level(encoder, (unsigned)(-1)))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_blocksize()... ");
+       if(!FLAC__stream_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_do_mid_side_stereo()... ");
+       if(!FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_loose_mid_side_stereo()... ");
+       if(!FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_max_lpc_order()... ");
+       if(!FLAC__stream_encoder_set_max_lpc_order(encoder, 0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_qlp_coeff_precision()... ");
+       if(!FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_do_qlp_coeff_prec_search()... ");
+       if(!FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_do_escape_coding()... ");
+       if(!FLAC__stream_encoder_set_do_escape_coding(encoder, false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_do_exhaustive_model_search()... ");
+       if(!FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_min_residual_partition_order()... ");
+       if(!FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_max_residual_partition_order()... ");
+       if(!FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_rice_parameter_search_dist()... ");
+       if(!FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_total_samples_estimate()... ");
+       if(!FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_set_metadata()... ");
+       if(!FLAC__stream_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILENAME) {
+               printf("opening file for FLAC output... ");
+               file = fopen(flacfilename(is_ogg), "w+b");
+               if(0 == file) {
+                       printf("ERROR (%s)\n", strerror(errno));
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       switch(layer) {
+               case LAYER_STREAM:
+                       printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file) :
+                               FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file);
+                       break;
+               case LAYER_SEEKABLE_STREAM:
+                       printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_encoder_init_ogg_stream(encoder, stream_encoder_read_callback_, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file) :
+                               FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file);
+                       break;
+               case LAYER_FILE:
+                       printf("testing FLAC__stream_encoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_encoder_init_ogg_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0) :
+                               FLAC__stream_encoder_init_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0);
+                       break;
+               case LAYER_FILENAME:
+                       printf("testing FLAC__stream_encoder_init_%sfile()... ", is_ogg? "ogg_":"");
+                       init_status = is_ogg?
+                               FLAC__stream_encoder_init_ogg_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0) :
+                               FLAC__stream_encoder_init_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0);
+                       break;
+               default:
+                       die_("internal error 001");
+                       return false;
+       }
+       if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+               return die_s_(0, encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_state()... ");
+       state = FLAC__stream_encoder_get_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)state, FLAC__StreamEncoderStateString[state]);
+
+       printf("testing FLAC__stream_encoder_get_verify_decoder_state()... ");
+       dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+       printf("returned state = %u (%s)... OK\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+       {
+               FLAC__uint64 absolute_sample;
+               unsigned frame_number;
+               unsigned channel;
+               unsigned sample;
+               FLAC__int32 expected;
+               FLAC__int32 got;
+
+               printf("testing FLAC__stream_encoder_get_verify_decoder_error_stats()... ");
+               FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+               printf("OK\n");
+       }
+
+       printf("testing FLAC__stream_encoder_get_verify()... ");
+       if(FLAC__stream_encoder_get_verify(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_streamable_subset()... ");
+       if(FLAC__stream_encoder_get_streamable_subset(encoder) != true) {
+               printf("FAILED, expected true, got false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_do_mid_side_stereo()... ");
+       if(FLAC__stream_encoder_get_do_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_loose_mid_side_stereo()... ");
+       if(FLAC__stream_encoder_get_loose_mid_side_stereo(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_channels()... ");
+       if(FLAC__stream_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, FLAC__stream_encoder_get_channels(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_bits_per_sample()... ");
+       if(FLAC__stream_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, FLAC__stream_encoder_get_bits_per_sample(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_sample_rate()... ");
+       if(FLAC__stream_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, FLAC__stream_encoder_get_sample_rate(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_blocksize()... ");
+       if(FLAC__stream_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) {
+               printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, FLAC__stream_encoder_get_blocksize(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_max_lpc_order()... ");
+       if(FLAC__stream_encoder_get_max_lpc_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_max_lpc_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_qlp_coeff_precision()... ");
+       (void)FLAC__stream_encoder_get_qlp_coeff_precision(encoder);
+       /* we asked the encoder to auto select this so we accept anything */
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_do_qlp_coeff_prec_search()... ");
+       if(FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_do_escape_coding()... ");
+       if(FLAC__stream_encoder_get_do_escape_coding(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_do_exhaustive_model_search()... ");
+       if(FLAC__stream_encoder_get_do_exhaustive_model_search(encoder) != false) {
+               printf("FAILED, expected false, got true\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_min_residual_partition_order()... ");
+       if(FLAC__stream_encoder_get_min_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_min_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_max_residual_partition_order()... ");
+       if(FLAC__stream_encoder_get_max_residual_partition_order(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_max_residual_partition_order(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_rice_parameter_search_dist()... ");
+       if(FLAC__stream_encoder_get_rice_parameter_search_dist(encoder) != 0) {
+               printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_rice_parameter_search_dist(encoder));
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_get_total_samples_estimate()... ");
+       if(FLAC__stream_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) {
+#ifdef _MSC_VER
+               printf("FAILED, expected %I64u, got %I64u\n", streaminfo_.data.stream_info.total_samples, FLAC__stream_encoder_get_total_samples_estimate(encoder));
+#else
+               printf("FAILED, expected %llu, got %llu\n", (unsigned long long)streaminfo_.data.stream_info.total_samples, (unsigned long long)FLAC__stream_encoder_get_total_samples_estimate(encoder));
+#endif
+               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 FLAC__stream_encoder_process()... ");
+       if(!FLAC__stream_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_process_interleaved()... ");
+       if(!FLAC__stream_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32)))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       printf("testing FLAC__stream_encoder_finish()... ");
+       if(!FLAC__stream_encoder_finish(encoder))
+               return die_s_("returned false", encoder);
+       printf("OK\n");
+
+       if(layer < LAYER_FILE)
+               fclose(file);
+
+       printf("testing FLAC__stream_encoder_delete()... ");
+       FLAC__stream_encoder_delete(encoder);
+       printf("OK\n");
+
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+FLAC__bool test_encoders(void)
+{
+       FLAC__bool is_ogg = false;
+
+       while(1) {
+               init_metadata_blocks_();
+
+               if(!test_stream_encoder(LAYER_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_FILE, is_ogg))
+                       return false;
+
+               if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
+                       return false;
+
+               (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+               free_metadata_blocks_();
+
+               if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+                       break;
+               is_ogg = true;
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC/encoders.h b/src/test_libFLAC/encoders.h
new file mode 100644 (file)
index 0000000..86c3690
--- /dev/null
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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_ENCODERS_H
+#define FLAC__TEST_LIBFLAC_ENCODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_encoders(void);
+
+#endif
diff --git a/src/test_libFLAC/format.c b/src/test_libFLAC/format.c
new file mode 100644 (file)
index 0000000..7ac115d
--- /dev/null
@@ -0,0 +1,256 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "format.h"
+#include <stdio.h>
+
+static const char *true_false_string_[2] = { "false", "true" };
+
+static struct {
+       unsigned rate;
+       FLAC__bool valid;
+       FLAC__bool subset;
+} SAMPLE_RATES[] = {
+       { 0      , false, false },
+       { 1      , true , true  },
+       { 9      , true , true  },
+       { 10     , true , true  },
+       { 4000   , true , true  },
+       { 8000   , true , true  },
+       { 11025  , true , true  },
+       { 12000  , true , true  },
+       { 16000  , true , true  },
+       { 22050  , true , true  },
+       { 24000  , true , true  },
+       { 32000  , true , true  },
+       { 32768  , true , true  },
+       { 44100  , true , true  },
+       { 48000  , true , true  },
+       { 65000  , true , true  },
+       { 65535  , true , true  },
+       { 65536  , true , false },
+       { 65540  , true , true  },
+       { 65550  , true , true  },
+       { 65555  , true , false },
+       { 66000  , true , true  },
+       { 66001  , true , false },
+       { 96000  , true , true  },
+       { 100000 , true , true  },
+       { 100001 , true , false },
+       { 192000 , true , true  },
+       { 500000 , true , true  },
+       { 500001 , true , false },
+       { 500010 , true , true  },
+       { 655349 , true , false },
+       { 655350 , true , true  },
+       { 655351 , false, false },
+       { 655360 , false, false },
+       { 700000 , false, false },
+       { 700010 , false, false },
+       { 1000000, false, false },
+       { 1100000, false, false }
+};
+
+static struct {
+       const char *string;
+       FLAC__bool valid;
+} VCENTRY_NAMES[] = {
+       { ""    , true  },
+       { "a"   , true  },
+       { "="   , false },
+       { "a="  , false },
+       { "\x01", false },
+       { "\x1f", false },
+       { "\x7d", true  },
+       { "\x7e", false },
+       { "\xff", false }
+};
+
+static struct {
+       unsigned length;
+       const FLAC__byte *string;
+       FLAC__bool valid;
+} VCENTRY_VALUES[] = {
+       { 0, (const FLAC__byte*)""            , true  },
+       { 1, (const FLAC__byte*)""            , true  },
+       { 1, (const FLAC__byte*)"\x01"        , true  },
+       { 1, (const FLAC__byte*)"\x7f"        , true  },
+       { 1, (const FLAC__byte*)"\x80"        , false },
+       { 1, (const FLAC__byte*)"\x81"        , false },
+       { 1, (const FLAC__byte*)"\xc0"        , false },
+       { 1, (const FLAC__byte*)"\xe0"        , false },
+       { 1, (const FLAC__byte*)"\xf0"        , false },
+       { 2, (const FLAC__byte*)"\xc0\x41"    , false },
+       { 2, (const FLAC__byte*)"\xc1\x41"    , false },
+       { 2, (const FLAC__byte*)"\xc0\x85"    , false }, /* non-shortest form */
+       { 2, (const FLAC__byte*)"\xc1\x85"    , false }, /* non-shortest form */
+       { 2, (const FLAC__byte*)"\xc2\x85"    , true  },
+       { 2, (const FLAC__byte*)"\xe0\x41"    , false },
+       { 2, (const FLAC__byte*)"\xe1\x41"    , false },
+       { 2, (const FLAC__byte*)"\xe0\x85"    , false },
+       { 2, (const FLAC__byte*)"\xe1\x85"    , false },
+       { 3, (const FLAC__byte*)"\xe0\x85\x41", false },
+       { 3, (const FLAC__byte*)"\xe1\x85\x41", false },
+       { 3, (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+       { 3, (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+       { 3, (const FLAC__byte*)"\xe0\xa5\x80", true  },
+       { 3, (const FLAC__byte*)"\xe1\x85\x80", true  },
+       { 3, (const FLAC__byte*)"\xe1\x95\x80", true  },
+       { 3, (const FLAC__byte*)"\xe1\xa5\x80", true  }
+};
+
+static struct {
+       const FLAC__byte *string;
+       FLAC__bool valid;
+} VCENTRY_VALUES_NT[] = {
+       { (const FLAC__byte*)""            , true  },
+       { (const FLAC__byte*)"\x01"        , true  },
+       { (const FLAC__byte*)"\x7f"        , true  },
+       { (const FLAC__byte*)"\x80"        , false },
+       { (const FLAC__byte*)"\x81"        , false },
+       { (const FLAC__byte*)"\xc0"        , false },
+       { (const FLAC__byte*)"\xe0"        , false },
+       { (const FLAC__byte*)"\xf0"        , false },
+       { (const FLAC__byte*)"\xc0\x41"    , false },
+       { (const FLAC__byte*)"\xc1\x41"    , false },
+       { (const FLAC__byte*)"\xc0\x85"    , false }, /* non-shortest form */
+       { (const FLAC__byte*)"\xc1\x85"    , false }, /* non-shortest form */
+       { (const FLAC__byte*)"\xc2\x85"    , true  },
+       { (const FLAC__byte*)"\xe0\x41"    , false },
+       { (const FLAC__byte*)"\xe1\x41"    , false },
+       { (const FLAC__byte*)"\xe0\x85"    , false },
+       { (const FLAC__byte*)"\xe1\x85"    , false },
+       { (const FLAC__byte*)"\xe0\x85\x41", false },
+       { (const FLAC__byte*)"\xe1\x85\x41", false },
+       { (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+       { (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+       { (const FLAC__byte*)"\xe0\xa5\x80", true  },
+       { (const FLAC__byte*)"\xe1\x85\x80", true  },
+       { (const FLAC__byte*)"\xe1\x95\x80", true  },
+       { (const FLAC__byte*)"\xe1\xa5\x80", true  }
+};
+
+static struct {
+       unsigned length;
+       const FLAC__byte *string;
+       FLAC__bool valid;
+} VCENTRIES[] = {
+       { 0, (const FLAC__byte*)""              , false },
+       { 1, (const FLAC__byte*)"a"             , false },
+       { 1, (const FLAC__byte*)"="             , true  },
+       { 2, (const FLAC__byte*)"a="            , true  },
+       { 2, (const FLAC__byte*)"\x01="         , false },
+       { 2, (const FLAC__byte*)"\x1f="         , false },
+       { 2, (const FLAC__byte*)"\x7d="         , true  },
+       { 2, (const FLAC__byte*)"\x7e="         , false },
+       { 2, (const FLAC__byte*)"\xff="         , false },
+       { 3, (const FLAC__byte*)"a=\x01"        , true  },
+       { 3, (const FLAC__byte*)"a=\x7f"        , true  },
+       { 3, (const FLAC__byte*)"a=\x80"        , false },
+       { 3, (const FLAC__byte*)"a=\x81"        , false },
+       { 3, (const FLAC__byte*)"a=\xc0"        , false },
+       { 3, (const FLAC__byte*)"a=\xe0"        , false },
+       { 3, (const FLAC__byte*)"a=\xf0"        , false },
+       { 4, (const FLAC__byte*)"a=\xc0\x41"    , false },
+       { 4, (const FLAC__byte*)"a=\xc1\x41"    , false },
+       { 4, (const FLAC__byte*)"a=\xc0\x85"    , false }, /* non-shortest form */
+       { 4, (const FLAC__byte*)"a=\xc1\x85"    , false }, /* non-shortest form */
+       { 4, (const FLAC__byte*)"a=\xc2\x85"    , true  },
+       { 4, (const FLAC__byte*)"a=\xe0\x41"    , false },
+       { 4, (const FLAC__byte*)"a=\xe1\x41"    , false },
+       { 4, (const FLAC__byte*)"a=\xe0\x85"    , false },
+       { 4, (const FLAC__byte*)"a=\xe1\x85"    , false },
+       { 5, (const FLAC__byte*)"a=\xe0\x85\x41", false },
+       { 5, (const FLAC__byte*)"a=\xe1\x85\x41", false },
+       { 5, (const FLAC__byte*)"a=\xe0\x85\x80", false }, /* non-shortest form */
+       { 5, (const FLAC__byte*)"a=\xe0\x95\x80", false }, /* non-shortest form */
+       { 5, (const FLAC__byte*)"a=\xe0\xa5\x80", true  },
+       { 5, (const FLAC__byte*)"a=\xe1\x85\x80", true  },
+       { 5, (const FLAC__byte*)"a=\xe1\x95\x80", true  },
+       { 5, (const FLAC__byte*)"a=\xe1\xa5\x80", true  }
+};
+
+FLAC__bool test_format(void)
+{
+       unsigned i;
+
+       printf("\n+++ libFLAC unit test: format\n\n");
+
+       for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+               printf("testing FLAC__format_sample_rate_is_valid(%u)... ", SAMPLE_RATES[i].rate);
+               if(FLAC__format_sample_rate_is_valid(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].valid) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].valid], true_false_string_[!SAMPLE_RATES[i].valid]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+               printf("testing FLAC__format_sample_rate_is_subset(%u)... ", SAMPLE_RATES[i].rate);
+               if(FLAC__format_sample_rate_is_subset(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].subset) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].subset], true_false_string_[!SAMPLE_RATES[i].subset]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       for(i = 0; i < sizeof(VCENTRY_NAMES)/sizeof(VCENTRY_NAMES[0]); i++) {
+               printf("testing FLAC__format_vorbiscomment_entry_name_is_legal(\"%s\")... ", VCENTRY_NAMES[i].string);
+               if(FLAC__format_vorbiscomment_entry_name_is_legal(VCENTRY_NAMES[i].string) != VCENTRY_NAMES[i].valid) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_NAMES[i].valid], true_false_string_[!VCENTRY_NAMES[i].valid]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       for(i = 0; i < sizeof(VCENTRY_VALUES)/sizeof(VCENTRY_VALUES[0]); i++) {
+               printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", %u)... ", VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length);
+               if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length) != VCENTRY_VALUES[i].valid) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES[i].valid], true_false_string_[!VCENTRY_VALUES[i].valid]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       for(i = 0; i < sizeof(VCENTRY_VALUES_NT)/sizeof(VCENTRY_VALUES_NT[0]); i++) {
+               printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", -1)... ", VCENTRY_VALUES_NT[i].string);
+               if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES_NT[i].string, (unsigned)(-1)) != VCENTRY_VALUES_NT[i].valid) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES_NT[i].valid], true_false_string_[!VCENTRY_VALUES_NT[i].valid]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       for(i = 0; i < sizeof(VCENTRIES)/sizeof(VCENTRIES[0]); i++) {
+               printf("testing FLAC__format_vorbiscomment_entry_is_legal(\"%s\", %u)... ", VCENTRIES[i].string, VCENTRIES[i].length);
+               if(FLAC__format_vorbiscomment_entry_is_legal(VCENTRIES[i].string, VCENTRIES[i].length) != VCENTRIES[i].valid) {
+                       printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRIES[i].valid], true_false_string_[!VCENTRIES[i].valid]);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       printf("\nPASSED!\n");
+       return true;
+}
diff --git a/src/test_libFLAC/format.h b/src/test_libFLAC/format.h
new file mode 100644 (file)
index 0000000..e48a0e0
--- /dev/null
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007  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_FORMAT_H
+#define FLAC__TEST_LIBFLAC_FORMAT_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_format(void);
+
+#endif
diff --git a/src/test_libFLAC/main.c b/src/test_libFLAC/main.c
new file mode 100644 (file)
index 0000000..1807ff5
--- /dev/null
@@ -0,0 +1,49 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "bitwriter.h"
+#include "decoders.h"
+#include "encoders.h"
+#include "format.h"
+#include "metadata.h"
+
+int main(int argc, char *argv[])
+{
+       (void)argc, (void)argv;
+
+       if(!test_bitwriter())
+               return 1;
+
+       if(!test_format())
+               return 1;
+
+       if(!test_encoders())
+               return 1;
+
+       if(!test_decoders())
+               return 1;
+
+       if(!test_metadata())
+               return 1;
+
+       return 0;
+}
diff --git a/src/test_libFLAC/metadata.c b/src/test_libFLAC/metadata.c
new file mode 100644 (file)
index 0000000..aacb6bf
--- /dev/null
@@ -0,0 +1,40 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "metadata.h"
+#include <stdio.h>
+
+extern FLAC__bool test_metadata_object(void);
+extern FLAC__bool test_metadata_file_manipulation(void);
+
+FLAC__bool test_metadata(void)
+{
+       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..0551564
--- /dev/null
@@ -0,0 +1,28 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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_METADATA_H
+#define FLAC__TEST_LIBFLAC_METADATA_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_metadata(void);
+FLAC__bool test_metadata_file_manipulation(void);
+FLAC__bool test_metadata_object(void);
+
+#endif
diff --git a/src/test_libFLAC/metadata_manip.c b/src/test_libFLAC/metadata_manip.c
new file mode 100644 (file)
index 0000000..b387531
--- /dev/null
@@ -0,0 +1,2133 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod() */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+#include "metadata.h"
+
+
+/******************************************************************************
+       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__StreamDecoder 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;
+
+/* our copy of the metadata in flacfilename() */
+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 const char *flacfilename(FLAC__bool is_ogg)
+{
+       return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_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 *iterator)
+{
+       printf("ERROR: %s\n", msg);
+       printf("       status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
+       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 char *strdup_or_die_(const char *s)
+{
+       char *x = strdup(s);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+               exit(1);
+       }
+       return x;
+}
+
+/* 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_clone(block)))
+                       return die_("during FLAC__metadata_object_clone()");
+       }
+       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_clone(block)))
+                       return die_("during FLAC__metadata_object_clone()");
+       }
+       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;
+       }
+}
+
+/*
+ * This wad of functions supports filename- and callback-based chain reading/writing.
+ * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
+ */
+static FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+       static const char *tempfile_suffix = ".metadata_edit";
+
+       if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
+               return false;
+       strcpy(*tempfilename, filename);
+       strcat(*tempfilename, tempfile_suffix);
+
+       if(0 == (*tempfile = fopen(*tempfilename, "wb")))
+               return false;
+
+       return true;
+}
+
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+       if(0 != *tempfile) {
+               (void)fclose(*tempfile);
+               *tempfile = 0;
+       }
+
+       if(0 != *tempfilename) {
+               (void)unlink(*tempfilename);
+               free(*tempfilename);
+               *tempfilename = 0;
+       }
+}
+
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != tempfile);
+       FLAC__ASSERT(0 != tempfilename);
+       FLAC__ASSERT(0 != *tempfilename);
+
+       if(0 != *tempfile) {
+               (void)fclose(*tempfile);
+               *tempfile = 0;
+       }
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+       /* on some flavors of windows, rename() will fail if the destination already exists */
+       if(unlink(filename) < 0) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+#endif
+
+       if(0 != rename(*tempfilename, filename)) {
+               cleanup_tempfile_(tempfile, tempfilename);
+               return false;
+       }
+
+       cleanup_tempfile_(tempfile, tempfilename);
+
+       return true;
+}
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+       return (0 == stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct stat *stats)
+{
+       struct utimbuf srctime;
+
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != stats);
+
+       srctime.actime = stats->st_atime;
+       srctime.modtime = stats->st_mtime;
+       (void)chmod(filename, stats->st_mode);
+       (void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+       (void)chown(filename, stats->st_uid, -1);
+       (void)chown(filename, -1, stats->st_gid);
+#endif
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
+{
+       FILE *stream = (FILE*)handle;
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#endif
+
+static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+       off_t o = (off_t)offset;
+       FLAC__ASSERT(offset == o);
+       return fseeko((FILE*)handle, o, whence);
+}
+
+static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
+{
+       return ftello((FILE*)handle);
+}
+
+static int chain_eof_cb_(FLAC__IOHandle handle)
+{
+       return feof((FILE*)handle);
+}
+
+static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
+{
+       if(filename_based)
+               return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
+       else {
+               FLAC__IOCallbacks callbacks;
+
+               memset(&callbacks, 0, sizeof(callbacks));
+               callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+               callbacks.write = chain_write_cb_;
+#else
+               callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+               callbacks.seek = chain_seek_cb_;
+               callbacks.eof = chain_eof_cb_;
+
+               if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+                       struct stat stats;
+                       FILE *file, *tempfile = 0;
+                       char *tempfilename;
+                       if(preserve_file_stats) {
+                               if(!get_file_stats_(filename, &stats))
+                                       return false;
+                       }
+                       if(0 == (file = fopen(filename, "rb")))
+                               return false; /*@@@@ chain status still says OK though */
+                       if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
+                               fclose(file);
+                               cleanup_tempfile_(&tempfile, &tempfilename);
+                               return false; /*@@@@ chain status still says OK though */
+                       }
+                       if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) {
+                               fclose(file);
+                               fclose(tempfile);
+                               return false;
+                       }
+                       fclose(file);
+                       fclose(tempfile);
+                       file = tempfile = 0;
+                       if(!transport_tempfile_(filename, &tempfile, &tempfilename))
+                               return false;
+                       if(preserve_file_stats)
+                               set_file_stats_(filename, &stats);
+               }
+               else {
+                       FILE *file = fopen(filename, "r+b");
+                       if(0 == file)
+                               return false; /*@@@@ chain status still says OK though */
+                       if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
+                               return false;
+                       fclose(file);
+               }
+       }
+
+       return true;
+}
+
+static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+       if(filename_based)
+               return is_ogg?
+                       FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) :
+                       FLAC__metadata_chain_read(chain, flacfilename(is_ogg))
+               ;
+       else {
+               FLAC__IOCallbacks callbacks;
+
+               memset(&callbacks, 0, sizeof(callbacks));
+               callbacks.read = (FLAC__IOCallback_Read)fread;
+               callbacks.seek = chain_seek_cb_;
+               callbacks.tell = chain_tell_cb_;
+
+               {
+                       FLAC__bool ret;
+                       FILE *file = fopen(filename, "rb");
+                       if(0 == file)
+                               return false; /*@@@@ chain status still says OK though */
+                       ret = is_ogg?
+                               FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) :
+                               FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)
+                       ;
+                       fclose(file);
+                       return ret;
+               }
+       }
+}
+
+/* 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(!mutils__compare_block(our_metadata_.blocks[i], block)) {
+                       FLAC__metadata_iterator_delete(iterator);
+                       return die_("metadata block mismatch");
+               }
+
+               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(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
+                       return die_("metadata block mismatch");
+       }
+
+       printf("PASSED\n");
+
+       return true;
+}
+
+/* decoder callbacks for checking the file */
+
+static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *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;
+}
+
+/* this version pays no attention to the metadata */
+static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *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__StreamDecoder *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(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
+                       (void)die_("metadata block mismatch");
+                       dcd->error_occurred = true;
+               }
+       }
+       mc_our_block_number_++;
+}
+
+static void decoder_error_callback_(const FLAC__StreamDecoder *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);
+}
+
+static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg)
+{
+       FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+       FLAC__StreamMetadata *metadata[4];
+       unsigned i = 0, n = 0;
+
+       printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
+
+       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);
+
+       {
+               const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+               vorbiscomment.is_last = false;
+               vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               vorbiscomment.length = (4 + vendor_string_length) + 4;
+               vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
+               vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
+               memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+               vorbiscomment.data.vorbis_comment.num_comments = 0;
+               vorbiscomment.data.vorbis_comment.comments = 0;
+       }
+
+       {
+               if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
+                       return die_("priming our metadata");
+               cuesheet->is_last = false;
+               strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
+               cuesheet->data.cue_sheet.lead_in = 123;
+               cuesheet->data.cue_sheet.is_cd = false;
+               if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+                       return die_("priming our metadata");
+               cuesheet->data.cue_sheet.tracks[0].number = 1;
+               if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+                       return die_("priming our metadata");
+       }
+
+       {
+               picture.is_last = false;
+               picture.type = FLAC__METADATA_TYPE_PICTURE;
+               picture.length =
+                       (
+                               FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+                               FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+                               FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+                               FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+                       ) / 8
+               ;
+               picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+               picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+               picture.length += strlen(picture.data.picture.mime_type);
+               picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+               picture.length += strlen((const char *)picture.data.picture.description);
+               picture.data.picture.width = 300;
+               picture.data.picture.height = 300;
+               picture.data.picture.depth = 24;
+               picture.data.picture.colors = 0;
+               picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+               picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+               picture.length += picture.data.picture.data_length;
+       }
+
+       padding.is_last = true;
+       padding.type = FLAC__METADATA_TYPE_PADDING;
+       padding.length = 1234;
+
+       metadata[n++] = &vorbiscomment;
+       if(include_extras) {
+               metadata[n++] = cuesheet;
+               metadata[n++] = &picture;
+       }
+       metadata[n++] = &padding;
+
+       if(
+               !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
+               !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
+               (include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+               (include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
+               !insert_to_our_metadata_(&padding, i++, /*copy=*/true)
+       )
+               return die_("priming our metadata");
+
+       if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
+               return die_("creating the encoded file");
+
+       free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
+       free(picture.data.picture.mime_type);
+       free(picture.data.picture.description);
+       free(picture.data.picture.data);
+       if(!include_extras)
+               FLAC__metadata_object_delete(cuesheet);
+
+       return true;
+}
+
+static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback)
+{
+       const char *filename = flacfilename(is_ogg);
+       FLAC__StreamDecoder *decoder;
+       decoder_client_struct decoder_client_data;
+
+       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__stream_decoder_new()))
+               return die_("couldn't allocate decoder instance");
+
+       FLAC__stream_decoder_set_md5_checking(decoder, true);
+       FLAC__stream_decoder_set_metadata_respond_all(decoder);
+       if(
+               (is_ogg?
+                       FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) :
+                       FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data)
+               ) != FLAC__STREAM_DECODER_INIT_STATUS_OK
+       ) {
+               (void)FLAC__stream_decoder_finish(decoder);
+               FLAC__stream_decoder_delete(decoder);
+               return die_("initializing decoder\n");
+       }
+       if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
+               (void)FLAC__stream_decoder_finish(decoder);
+               FLAC__stream_decoder_delete(decoder);
+               return die_("decoding file\n");
+       }
+
+       (void)FLAC__stream_decoder_finish(decoder);
+       FLAC__stream_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(!grabbag__file_change_stats(filename, read_only))
+               return die_("during grabbag__file_change_stats()");
+
+       return true;
+}
+
+static FLAC__bool remove_file_(const char *filename)
+{
+       while(our_metadata_.num_blocks > 0)
+               delete_from_our_metadata_(0);
+
+       if(!grabbag__file_remove_file(filename))
+               return die_("removing file");
+
+       return true;
+}
+
+static FLAC__bool test_level_0_(void)
+{
+       FLAC__StreamMetadata streaminfo;
+       FLAC__StreamMetadata *tags = 0;
+       FLAC__StreamMetadata *cuesheet = 0;
+       FLAC__StreamMetadata *picture = 0;
+
+       printf("\n\n++++++ testing level 0 interface\n");
+
+       if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+               return false;
+
+       printf("testing FLAC__metadata_get_streaminfo()... ");
+
+       if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo))
+               return die_("during FLAC__metadata_get_streaminfo()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(streaminfo.data.stream_info.channels != 1)
+               return die_("mismatch in streaminfo.data.stream_info.channels");
+       if(streaminfo.data.stream_info.bits_per_sample != 8)
+               return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
+       if(streaminfo.data.stream_info.sample_rate != 44100)
+               return die_("mismatch in streaminfo.data.stream_info.sample_rate");
+       if(streaminfo.data.stream_info.min_blocksize != 576)
+               return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
+       if(streaminfo.data.stream_info.max_blocksize != 576)
+               return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
+
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_get_tags()... ");
+
+       if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags))
+               return die_("during FLAC__metadata_get_tags()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(tags->data.vorbis_comment.num_comments != 0)
+               return die_("mismatch in tags->data.vorbis_comment.num_comments");
+
+       printf("OK\n");
+
+       FLAC__metadata_object_delete(tags);
+
+       printf("testing FLAC__metadata_get_cuesheet()... ");
+
+       if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet))
+               return die_("during FLAC__metadata_get_cuesheet()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(cuesheet->data.cue_sheet.lead_in != 123)
+               return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
+
+       printf("OK\n");
+
+       FLAC__metadata_object_delete(cuesheet);
+
+       printf("testing FLAC__metadata_get_picture()... ");
+
+       if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
+               return die_("during FLAC__metadata_get_picture()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+               return die_("mismatch in picture->data.picture.type");
+
+       printf("OK\n");
+
+       FLAC__metadata_object_delete(picture);
+
+       if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+               return false;
+
+       return true;
+}
+
+static FLAC__bool test_level_1_(void)
+{
+       FLAC__Metadata_SimpleIterator *iterator;
+       FLAC__StreamMetadata *block, *app, *padding;
+       FLAC__byte data[1000];
+       unsigned our_current_position = 0;
+
+       /* initialize 'data' to avoid Valgrind errors */
+       memset(data, 0, sizeof(data));
+
+       printf("\n\n++++++ testing level 1 interface\n");
+
+       /************************************************************/
+
+       printf("simple iterator on read-only file\n");
+
+       if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
+               return false;
+
+       if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+               return false;
+
+       if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
+               return die_("FLAC__metadata_simple_iterator_new()");
+
+       if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+               return die_("FLAC__metadata_simple_iterator_init() returned false");
+
+       printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
+       if(FLAC__metadata_simple_iterator_is_writable(iterator))
+               return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
+
+       printf("iterate forwards\n");
+
+       if(FLAC__metadata_simple_iterator_get_block_type(iterator) != 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(iterator)))
+               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");
+       FLAC__metadata_object_delete(block);
+
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("forward iterator ended early");
+       our_current_position++;
+
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("forward iterator ended early");
+       our_current_position++;
+
+       if(FLAC__metadata_simple_iterator_get_block_type(iterator) != 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(iterator)))
+               return die_("getting block 2");
+       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 PADDING length");
+       FLAC__metadata_object_delete(block);
+
+       if(FLAC__metadata_simple_iterator_next(iterator))
+               return die_("forward iterator returned true but should have returned false");
+
+       printf("iterate backwards\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("reverse iterator ended early");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("reverse iterator ended early");
+       if(FLAC__metadata_simple_iterator_prev(iterator))
+               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(iterator, (FLAC__StreamMetadata*)99, false))
+               printf("OK: 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(iterator);
+
+       /************************************************************/
+
+       printf("simple iterator on writable file\n");
+
+       if(!change_stats_(flacfilename(/*is_ogg=*/false), /*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 == (iterator = FLAC__metadata_simple_iterator_new()))
+               return die_("FLAC__metadata_simple_iterator_new()");
+
+       if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+               return die_("FLAC__metadata_simple_iterator_init() returned false");
+       our_current_position = 0;
+
+       printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
+
+       printf("[S]VP\ttry to write over STREAMINFO block...\n");
+       if(!FLAC__metadata_simple_iterator_set_block(iterator, 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]VP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
+       padding->length = 25;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       printf("SVP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
+       padding->length = 30;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[P]PP\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]PPP\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
+       if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]VPPP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]PPP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]PP\tdelete (middle block), replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
+       our_current_position--;
+
+       printf("S[V]PPP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]\tdelete (last block), replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       our_current_position--;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]\tdelete (last block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VP\tset STREAMINFO (change sample rate)\n");
+       FLAC__ASSERT(our_current_position == 0);
+       block = FLAC__metadata_simple_iterator_get_block(iterator);
+       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(iterator, block, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
+       FLAC__metadata_object_delete(block);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]VP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+       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_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVA[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+       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_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[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(iterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[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(iterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[A]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVAA[P]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVAAP[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(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVAAP[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(iterator, app, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVAAP[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(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVAAP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVA[P]\tinsert PADDING after\n");
+       padding->length = 5;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVAP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVA[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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(iterator, padding, true))
+               return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[P]\tinsert PADDING after\n");
+       if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVP[P]\tinsert PADDING after\n");
+       padding->length = 5;
+       if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+       if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+               return false;
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVPP[P]\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SVP[P]P\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("SV[P]PP\tprev\n");
+       if(!FLAC__metadata_simple_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]PP\tnext\n");
+       if(!FLAC__metadata_simple_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
+       if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+               return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+       delete_from_our_metadata_(our_current_position--);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("S[V]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(iterator, app, true))
+               return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+       if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("delete simple iterator\n");
+
+       FLAC__metadata_simple_iterator_delete(iterator);
+
+       FLAC__metadata_object_delete(app);
+       FLAC__metadata_object_delete(padding);
+
+       if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+               return false;
+
+       return true;
+}
+
+static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+       FLAC__Metadata_Iterator *iterator;
+       FLAC__Metadata_Chain *chain;
+       FLAC__StreamMetadata *block, *app, *padding;
+       FLAC__byte data[2000];
+       unsigned our_current_position;
+
+       /* initialize 'data' to avoid Valgrind errors */
+       memset(data, 0, sizeof(data));
+
+       printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
+
+       printf("generate read-only file\n");
+
+       if(!generate_file_(/*include_extras=*/false, is_ogg))
+               return false;
+
+       if(!change_stats_(flacfilename(is_ogg), /*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(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
+               return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+       printf("[S]VP\ttest initial metadata\n");
+
+       if(!compare_chain_(chain, 0, 0))
+               return false;
+       if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       if(is_ogg)
+               goto end;
+
+       printf("switch file to read-write\n");
+
+       if(!change_stats_(flacfilename(is_ogg), /*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]VP\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(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("[S]VP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[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(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]\tshrink APPLICATION, don't use padding\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]\tgrow APPLICATION, don't use padding\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[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_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+       if(0 == (app = FLAC__metadata_object_clone(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(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV[A]\tprev\n");
+       if(!FLAC__metadata_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("S[V]A\tprev\n");
+       if(!FLAC__metadata_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]VA\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]VP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]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("SV[P]A\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_clone(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("SV[P]PA\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_clone(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("SV[P]PPA\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVP[P]PA\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVPP[P]A\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SVPPP[A]\tinsert PADDING after\n");
+       if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+               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("SVPPPA[P]\tinsert PADDING before\n");
+       if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+               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("SVPPPAPP\tmerge padding\n");
+       FLAC__metadata_chain_merge_padding(chain);
+       our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
+       our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
+       our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
+       delete_from_our_metadata_(7);
+       delete_from_our_metadata_(4);
+       delete_from_our_metadata_(3);
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SVPAP\tsort padding\n");
+       FLAC__metadata_chain_sort_padding(chain);
+       our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
+       delete_from_our_metadata_(2);
+
+       if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, 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]VAP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("S[V]AP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[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[V]PP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[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[V]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[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[V]P\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+       our_current_position++;
+
+       printf("SV[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[V]\tprev\n");
+       if(!FLAC__metadata_iterator_prev(iterator))
+               return die_("iterator ended early\n");
+       our_current_position--;
+
+       printf("[S]V\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("SV\tmerge padding\n");
+       FLAC__metadata_chain_merge_padding(chain);
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+       printf("SV\tsort padding\n");
+       FLAC__metadata_chain_sort_padding(chain);
+
+       if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+               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_(is_ogg, decoder_metadata_callback_compare_))
+               return false;
+
+end:
+       printf("delete chain\n");
+
+       FLAC__metadata_chain_delete(chain);
+
+       if(!remove_file_(flacfilename(is_ogg)))
+               return false;
+
+       return true;
+}
+
+static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
+{
+       FLAC__Metadata_Iterator *iterator;
+       FLAC__Metadata_Chain *chain;
+       FLAC__IOCallbacks callbacks;
+
+       memset(&callbacks, 0, sizeof(callbacks));
+       callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+       callbacks.write = chain_write_cb_;
+#else
+       callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+       callbacks.seek = chain_seek_cb_;
+       callbacks.tell = chain_tell_cb_;
+       callbacks.eof = chain_eof_cb_;
+
+       printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
+
+       printf("generate file\n");
+
+       if(!generate_file_(/*include_extras=*/false, is_ogg))
+               return false;
+
+       printf("create chain\n");
+
+       if(0 == (chain = FLAC__metadata_chain_new()))
+               return die_("allocating chain");
+
+       printf("read chain (filename-based)\n");
+
+       if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+               return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+       printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+       {
+               if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+                       return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+               if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+               printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (filename-based)\n");
+
+       if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+               return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+       printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+       {
+               if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+                       return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+               if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+               printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+               }
+               fclose(file);
+       }
+
+       printf("write chain with wrong method FLAC__metadata_chain_write()\n");
+       {
+               if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+                       return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+               if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+               printf("  OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+               }
+               fclose(file);
+       }
+
+       printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+       if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+               printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
+       else
+               return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
+
+       printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+       {
+               if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+                       return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+               if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+               printf("  OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+       }
+
+       printf("read chain (callback-based)\n");
+       {
+               FILE *file = fopen(flacfilename(is_ogg), "rb");
+               if(0 == file)
+                       return die_("opening file");
+               if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+                       fclose(file);
+                       return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+               }
+               fclose(file);
+       }
+
+       printf("create iterator\n");
+       if(0 == (iterator = FLAC__metadata_iterator_new()))
+               return die_("allocating memory for iterator");
+
+       FLAC__metadata_iterator_init(iterator, chain);
+
+       printf("[S]VP\tnext\n");
+       if(!FLAC__metadata_iterator_next(iterator))
+               return die_("iterator ended early\n");
+
+       printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
+       if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+               return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
+
+       printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+       if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+               printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
+       else
+               return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
+
+       printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+       {
+               if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+                       return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+               if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+                       return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+               printf("  OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+       }
+
+       printf("delete iterator\n");
+
+       FLAC__metadata_iterator_delete(iterator);
+
+       printf("delete chain\n");
+
+       FLAC__metadata_chain_delete(chain);
+
+       if(!remove_file_(flacfilename(is_ogg)))
+               return false;
+
+       return true;
+}
+
+FLAC__bool test_metadata_file_manipulation(void)
+{
+       printf("\n+++ libFLAC 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_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
+               return false;
+       if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
+               return false;
+       if(!test_level_2_misc_(/*is_ogg=*/false))
+               return false;
+
+       if(FLAC_API_SUPPORTS_OGG_FLAC) {
+               if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
+                       return false;
+               if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
+                       return false;
+#if 0
+               /* when ogg flac write is supported, will have to add this: */
+               if(!test_level_2_misc_(/*is_ogg=*/true))
+                       return false;
+#endif
+       }
+
+       return true;
+}
diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c
new file mode 100644 (file)
index 0000000..617248f
--- /dev/null
@@ -0,0 +1,2299 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "metadata.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+static FLAC__byte *make_dummydata_(FLAC__byte *dummydata, unsigned len)
+{
+       FLAC__byte *ret;
+
+       if(0 == (ret = (FLAC__byte*)malloc(len))) {
+               printf("FAILED, malloc error\n");
+               exit(1);
+       }
+       else
+               memcpy(ret, dummydata, len);
+
+       return ret;
+}
+
+static FLAC__bool compare_track_(const FLAC__StreamMetadata_CueSheet_Track *from, const FLAC__StreamMetadata_CueSheet_Track *to)
+{
+       unsigned i;
+
+       if(from->offset != to->offset) {
+#ifdef _MSC_VER
+               printf("FAILED, track offset mismatch, expected %I64u, got %I64u\n", to->offset, from->offset);
+#else
+               printf("FAILED, track offset mismatch, expected %llu, got %llu\n", (unsigned long long)to->offset, (unsigned long long)from->offset);
+#endif
+               return false;
+       }
+       if(from->number != to->number) {
+               printf("FAILED, track number mismatch, expected %u, got %u\n", (unsigned)to->number, (unsigned)from->number);
+               return false;
+       }
+       if(0 != strcmp(from->isrc, to->isrc)) {
+               printf("FAILED, track number mismatch, expected %s, got %s\n", to->isrc, from->isrc);
+               return false;
+       }
+       if(from->type != to->type) {
+               printf("FAILED, track type mismatch, expected %u, got %u\n", (unsigned)to->type, (unsigned)from->type);
+               return false;
+       }
+       if(from->pre_emphasis != to->pre_emphasis) {
+               printf("FAILED, track pre_emphasis mismatch, expected %u, got %u\n", (unsigned)to->pre_emphasis, (unsigned)from->pre_emphasis);
+               return false;
+       }
+       if(from->num_indices != to->num_indices) {
+               printf("FAILED, track num_indices mismatch, expected %u, got %u\n", (unsigned)to->num_indices, (unsigned)from->num_indices);
+               return false;
+       }
+       if(0 == to->indices || 0 == from->indices) {
+               if(to->indices != from->indices) {
+                       printf("FAILED, track indices mismatch\n");
+                       return false;
+               }
+       }
+       else {
+               for(i = 0; i < to->num_indices; i++) {
+                       if(from->indices[i].offset != to->indices[i].offset) {
+#ifdef _MSC_VER
+                               printf("FAILED, track indices[%u].offset mismatch, expected %I64u, got %I64u\n", i, to->indices[i].offset, from->indices[i].offset);
+#else
+                               printf("FAILED, track indices[%u].offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)to->indices[i].offset, (unsigned long long)from->indices[i].offset);
+#endif
+                               return false;
+                       }
+                       if(from->indices[i].number != to->indices[i].number) {
+                               printf("FAILED, track indices[%u].number mismatch, expected %u, got %u\n", i, (unsigned)to->indices[i].number, (unsigned)from->indices[i].number);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+static FLAC__bool compare_seekpoint_array_(const FLAC__StreamMetadata_SeekPoint *from, const FLAC__StreamMetadata_SeekPoint *to, unsigned n)
+{
+       unsigned i;
+
+       FLAC__ASSERT(0 != from);
+       FLAC__ASSERT(0 != to);
+
+       for(i = 0; i < n; i++) {
+               if(from[i].sample_number != to[i].sample_number) {
+#ifdef _MSC_VER
+                       printf("FAILED, point[%u].sample_number mismatch, expected %I64u, got %I64u\n", i, to[i].sample_number, from[i].sample_number);
+#else
+                       printf("FAILED, point[%u].sample_number mismatch, expected %llu, got %llu\n", i, (unsigned long long)to[i].sample_number, (unsigned long long)from[i].sample_number);
+#endif
+                       return false;
+               }
+               if(from[i].stream_offset != to[i].stream_offset) {
+#ifdef _MSC_VER
+                       printf("FAILED, point[%u].stream_offset mismatch, expected %I64u, got %I64u\n", i, to[i].stream_offset, from[i].stream_offset);
+#else
+                       printf("FAILED, point[%u].stream_offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)to[i].stream_offset, (unsigned long long)from[i].stream_offset);
+#endif
+                       return false;
+               }
+               if(from[i].frame_samples != to[i].frame_samples) {
+                       printf("FAILED, point[%u].frame_samples mismatch, expected %u, got %u\n", i, to[i].frame_samples, from[i].frame_samples);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static FLAC__bool check_seektable_(const FLAC__StreamMetadata *block, unsigned num_points, const FLAC__StreamMetadata_SeekPoint *array)
+{
+       const unsigned expected_length = num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       if(block->data.seek_table.num_points != num_points) {
+               printf("FAILED, expected %u point, got %u\n", num_points, block->data.seek_table.num_points);
+               return false;
+       }
+       if(0 == array) {
+               if(0 != block->data.seek_table.points) {
+                       printf("FAILED, 'points' pointer is not null\n");
+                       return false;
+               }
+       }
+       else {
+               if(!compare_seekpoint_array_(block->data.seek_table.points, array, num_points))
+                       return false;
+       }
+       printf("OK\n");
+
+       return true;
+}
+
+static void entry_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field)
+{
+       entry->length = strlen(field);
+       entry->entry = (FLAC__byte*)malloc(entry->length+1);
+       FLAC__ASSERT(0 != entry->entry);
+       memcpy(entry->entry, field, entry->length);
+       entry->entry[entry->length] = '\0';
+}
+
+static void entry_clone_(FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+       FLAC__byte *x = (FLAC__byte*)malloc(entry->length+1);
+       FLAC__ASSERT(0 != x);
+       memcpy(x, entry->entry, entry->length);
+       x[entry->length] = '\0';
+       entry->entry = x;
+}
+
+static void vc_calc_len_(FLAC__StreamMetadata *block)
+{
+       const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+       unsigned i;
+
+       block->length = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+       block->length += vc->vendor_string.length;
+       block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+       for(i = 0; i < vc->num_comments; i++) {
+               block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+               block->length += vc->comments[i].length;
+       }
+}
+
+static void vc_resize_(FLAC__StreamMetadata *block, unsigned num)
+{
+       FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+
+       if(vc->num_comments != 0) {
+               FLAC__ASSERT(0 != vc->comments);
+               if(num < vc->num_comments) {
+                       unsigned i;
+                       for(i = num; i < vc->num_comments; i++) {
+                               if(0 != vc->comments[i].entry)
+                                       free(vc->comments[i].entry);
+                       }
+               }
+       }
+       if(num == 0) {
+               if(0 != vc->comments) {
+                       free(vc->comments);
+                       vc->comments = 0;
+               }
+       }
+       else {
+               vc->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(vc->comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*num);
+               FLAC__ASSERT(0 != vc->comments);
+               if(num > vc->num_comments)
+                       memset(vc->comments+vc->num_comments, 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(num-vc->num_comments));
+       }
+
+       vc->num_comments = num;
+       vc_calc_len_(block);
+}
+
+static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, unsigned start)
+{
+       const unsigned n = strlen(name);
+       unsigned i;
+       for(i = start; i < block->data.vorbis_comment.num_comments; i++) {
+               const FLAC__StreamMetadata_VorbisComment_Entry *entry = &block->data.vorbis_comment.comments[i];
+               if(entry->length > n && 0 == strncmp((const char *)entry->entry, name, n) && entry->entry[n] == '=')
+                       return (int)i;
+       }
+       return -1;
+}
+
+static void vc_set_vs_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field)
+{
+       if(0 != block->data.vorbis_comment.vendor_string.entry)
+               free(block->data.vorbis_comment.vendor_string.entry);
+       entry_new_(entry, field);
+       block->data.vorbis_comment.vendor_string = *entry;
+       vc_calc_len_(block);
+}
+
+static void vc_set_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, unsigned pos, const char *field)
+{
+       if(0 != block->data.vorbis_comment.comments[pos].entry)
+               free(block->data.vorbis_comment.comments[pos].entry);
+       entry_new_(entry, field);
+       block->data.vorbis_comment.comments[pos] = *entry;
+       vc_calc_len_(block);
+}
+
+static void vc_insert_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, unsigned pos, const char *field)
+{
+       vc_resize_(block, block->data.vorbis_comment.num_comments+1);
+       memmove(&block->data.vorbis_comment.comments[pos+1], &block->data.vorbis_comment.comments[pos], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-1-pos));
+       memset(&block->data.vorbis_comment.comments[pos], 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+       vc_set_new_(entry, block, pos, field);
+       vc_calc_len_(block);
+}
+
+static void vc_delete_(FLAC__StreamMetadata *block, unsigned pos)
+{
+       if(0 != block->data.vorbis_comment.comments[pos].entry)
+               free(block->data.vorbis_comment.comments[pos].entry);
+       memmove(&block->data.vorbis_comment.comments[pos], &block->data.vorbis_comment.comments[pos+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-pos-1));
+       block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].entry = 0;
+       block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].length = 0;
+       vc_resize_(block, block->data.vorbis_comment.num_comments-1);
+       vc_calc_len_(block);
+}
+
+static void vc_replace_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field, FLAC__bool all)
+{
+       int index;
+       char field_name[256];
+       const char *eq = strchr(field, '=');
+       FLAC__ASSERT(eq>field && (unsigned)(eq-field) < sizeof(field_name));
+       memcpy(field_name, field, eq-field);
+       field_name[eq-field]='\0';
+
+       index = vc_find_from_(block, field_name, 0);
+       if(index < 0)
+               vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field);
+       else {
+               vc_set_new_(entry, block, (unsigned)index, field);
+               if(all) {
+                       for(index = index+1; index >= 0 && (unsigned)index < block->data.vorbis_comment.num_comments; )
+                               if((index = vc_find_from_(block, field_name, (unsigned)index)) >= 0)
+                                       vc_delete_(block, (unsigned)index);
+               }
+       }
+
+       vc_calc_len_(block);
+}
+
+static void track_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+       track->offset = offset;
+       track->number = number;
+       memcpy(track->isrc, isrc, sizeof(track->isrc));
+       track->type = data;
+       track->pre_emphasis = pre_em;
+       track->num_indices = 0;
+       track->indices = 0;
+}
+
+static void track_clone_(FLAC__StreamMetadata_CueSheet_Track *track)
+{
+       if(track->num_indices > 0) {
+               size_t bytes = sizeof(FLAC__StreamMetadata_CueSheet_Index) * track->num_indices;
+               FLAC__StreamMetadata_CueSheet_Index *x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(bytes);
+               FLAC__ASSERT(0 != x);
+               memcpy(x, track->indices, bytes);
+               track->indices = x;
+       }
+}
+
+static void cs_calc_len_(FLAC__StreamMetadata *block)
+{
+       const FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+       unsigned i;
+
+       block->length = (
+               FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+       ) / 8;
+       block->length += cs->num_tracks * (
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+       ) / 8;
+       for(i = 0; i < cs->num_tracks; i++) {
+               block->length += cs->tracks[i].num_indices * (
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+               ) / 8;
+       }
+}
+
+static void tr_resize_(FLAC__StreamMetadata *block, unsigned track_num, unsigned num)
+{
+       FLAC__StreamMetadata_CueSheet_Track *tr;
+
+       FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+       tr = &block->data.cue_sheet.tracks[track_num];
+
+       if(tr->num_indices != 0) {
+               FLAC__ASSERT(0 != tr->indices);
+       }
+       if(num == 0) {
+               if(0 != tr->indices) {
+                       free(tr->indices);
+                       tr->indices = 0;
+               }
+       }
+       else {
+               tr->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(tr->indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)*num);
+               FLAC__ASSERT(0 != tr->indices);
+               if(num > tr->num_indices)
+                       memset(tr->indices+tr->num_indices, 0, sizeof(FLAC__StreamMetadata_CueSheet_Index)*(num-tr->num_indices));
+       }
+
+       tr->num_indices = num;
+       cs_calc_len_(block);
+}
+
+static void tr_set_new_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos, FLAC__StreamMetadata_CueSheet_Index index)
+{
+       FLAC__StreamMetadata_CueSheet_Track *tr;
+
+       FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+       tr = &block->data.cue_sheet.tracks[track_num];
+
+       FLAC__ASSERT(pos < tr->num_indices);
+
+       tr->indices[pos] = index;
+
+       cs_calc_len_(block);
+}
+
+static void tr_insert_new_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos, FLAC__StreamMetadata_CueSheet_Index index)
+{
+       FLAC__StreamMetadata_CueSheet_Track *tr;
+
+       FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+       tr = &block->data.cue_sheet.tracks[track_num];
+
+       FLAC__ASSERT(pos <= tr->num_indices);
+
+       tr_resize_(block, track_num, tr->num_indices+1);
+       memmove(&tr->indices[pos+1], &tr->indices[pos], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-1-pos));
+       tr_set_new_(block, track_num, pos, index);
+       cs_calc_len_(block);
+}
+
+static void tr_delete_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos)
+{
+       FLAC__StreamMetadata_CueSheet_Track *tr;
+
+       FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+       tr = &block->data.cue_sheet.tracks[track_num];
+
+       FLAC__ASSERT(pos <= tr->num_indices);
+
+       memmove(&tr->indices[pos], &tr->indices[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-pos-1));
+       tr_resize_(block, track_num, tr->num_indices-1);
+       cs_calc_len_(block);
+}
+
+static void cs_resize_(FLAC__StreamMetadata *block, unsigned num)
+{
+       FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+
+       if(cs->num_tracks != 0) {
+               FLAC__ASSERT(0 != cs->tracks);
+               if(num < cs->num_tracks) {
+                       unsigned i;
+                       for(i = num; i < cs->num_tracks; i++) {
+                               if(0 != cs->tracks[i].indices)
+                                       free(cs->tracks[i].indices);
+                       }
+               }
+       }
+       if(num == 0) {
+               if(0 != cs->tracks) {
+                       free(cs->tracks);
+                       cs->tracks = 0;
+               }
+       }
+       else {
+               cs->tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(cs->tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)*num);
+               FLAC__ASSERT(0 != cs->tracks);
+               if(num > cs->num_tracks)
+                       memset(cs->tracks+cs->num_tracks, 0, sizeof(FLAC__StreamMetadata_CueSheet_Track)*(num-cs->num_tracks));
+       }
+
+       cs->num_tracks = num;
+       cs_calc_len_(block);
+}
+
+static void cs_set_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+       track_new_(track, offset, number, isrc, data, pre_em);
+       block->data.cue_sheet.tracks[pos] = *track;
+       cs_calc_len_(block);
+}
+
+static void cs_insert_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+       cs_resize_(block, block->data.cue_sheet.num_tracks+1);
+       memmove(&block->data.cue_sheet.tracks[pos+1], &block->data.cue_sheet.tracks[pos], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-1-pos));
+       cs_set_new_(track, block, pos, offset, number, isrc, data, pre_em);
+       cs_calc_len_(block);
+}
+
+static void cs_delete_(FLAC__StreamMetadata *block, unsigned pos)
+{
+       if(0 != block->data.cue_sheet.tracks[pos].indices)
+               free(block->data.cue_sheet.tracks[pos].indices);
+       memmove(&block->data.cue_sheet.tracks[pos], &block->data.cue_sheet.tracks[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-pos-1));
+       block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].indices = 0;
+       block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].num_indices = 0;
+       cs_resize_(block, block->data.cue_sheet.num_tracks-1);
+       cs_calc_len_(block);
+}
+
+static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s)
+{
+       if(block->data.picture.mime_type) {
+               block->length -= strlen(block->data.picture.mime_type);
+               free(block->data.picture.mime_type);
+       }
+       block->data.picture.mime_type = strdup(s);
+       FLAC__ASSERT(block->data.picture.mime_type);
+       block->length += strlen(block->data.picture.mime_type);
+}
+
+static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s)
+{
+       if(block->data.picture.description) {
+               block->length -= strlen((const char *)block->data.picture.description);
+               free(block->data.picture.description);
+       }
+       block->data.picture.description = (FLAC__byte*)strdup((const char *)s);
+       FLAC__ASSERT(block->data.picture.description);
+       block->length += strlen((const char *)block->data.picture.description);
+}
+
+static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len)
+{
+       if(block->data.picture.data) {
+               block->length -= block->data.picture.data_length;
+               free(block->data.picture.data);
+       }
+       block->data.picture.data = (FLAC__byte*)strdup((const char *)data);
+       FLAC__ASSERT(block->data.picture.data);
+       block->data.picture.data_length = len;
+       block->length += len;
+}
+
+FLAC__bool test_metadata_object(void)
+{
+       FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture;
+       FLAC__StreamMetadata_SeekPoint seekpoint_array[14];
+       FLAC__StreamMetadata_VorbisComment_Entry entry;
+       FLAC__StreamMetadata_CueSheet_Index index;
+       FLAC__StreamMetadata_CueSheet_Track track;
+       unsigned i, expected_length, seekpoints;
+       int j;
+       static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' };
+
+       printf("\n+++ libFLAC unit test: metadata objects\n\n");
+
+
+       printf("testing STREAMINFO\n");
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing PADDING\n");
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = 0;
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing APPLICATION\n");
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_application_set_data(copy)... ");
+       if(!FLAC__metadata_object_application_set_data(block, dummydata, sizeof(dummydata), true/*copy*/)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+               printf("FAILED, data mismatch\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_application_set_data(own)... ");
+       if(!FLAC__metadata_object_application_set_data(block, make_dummydata_(dummydata, sizeof(dummydata)), sizeof(dummydata), false/*own*/)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+               printf("FAILED, data mismatch\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing SEEKTABLE\n");
+
+       for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+               seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+               seekpoint_array[i].stream_offset = 0;
+               seekpoint_array[i].frame_samples = 0;
+       }
+
+       seekpoints = 0;
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, 0))
+               return false;
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       seekpoints = 2;
+       printf("testing FLAC__metadata_object_seektable_resize_points(grow to %u)...", seekpoints);
+       if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoints = 1;
+       printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+       if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       printf("testing FLAC__metadata_object_seektable_is_legal()...");
+       if(!FLAC__metadata_object_seektable_is_legal(block)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       printf("OK\n");
+
+       seekpoints = 0;
+       printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+       if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, 0))
+               return false;
+
+       seekpoints++;
+       printf("testing FLAC__metadata_object_seektable_insert_point() on empty array...");
+       if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[0].sample_number = 1;
+       seekpoints++;
+       printf("testing FLAC__metadata_object_seektable_insert_point() on beginning of non-empty array...");
+       if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[1].sample_number = 2;
+       seekpoints++;
+       printf("testing FLAC__metadata_object_seektable_insert_point() on middle of non-empty array...");
+       if(!FLAC__metadata_object_seektable_insert_point(block, 1, seekpoint_array[1])) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[3].sample_number = 3;
+       seekpoints++;
+       printf("testing FLAC__metadata_object_seektable_insert_point() on end of non-empty array...");
+       if(!FLAC__metadata_object_seektable_insert_point(block, 3, seekpoint_array[3])) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       seekpoint_array[2].sample_number = seekpoint_array[3].sample_number;
+       seekpoints--;
+       printf("testing FLAC__metadata_object_seektable_delete_point() on middle of array...");
+       if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoints--;
+       printf("testing FLAC__metadata_object_seektable_delete_point() on end of array...");
+       if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoints--;
+       printf("testing FLAC__metadata_object_seektable_delete_point() on beginning of array...");
+       if(!FLAC__metadata_object_seektable_delete_point(block, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array+1))
+               return false;
+
+       printf("testing FLAC__metadata_object_seektable_set_point()...");
+       FLAC__metadata_object_seektable_set_point(block, 0, seekpoint_array[0]);
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+       /* seektable template functions */
+
+       for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+               seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+               seekpoint_array[i].stream_offset = 0;
+               seekpoint_array[i].frame_samples = 0;
+       }
+
+       seekpoints = 0;
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, 0))
+               return false;
+
+       seekpoints += 2;
+       printf("testing FLAC__metadata_object_seekpoint_template_append_placeholders()... ");
+       if(!FLAC__metadata_object_seektable_template_append_placeholders(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[seekpoints++].sample_number = 7;
+       printf("testing FLAC__metadata_object_seekpoint_template_append_point()... ");
+       if(!FLAC__metadata_object_seektable_template_append_point(block, 7)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       {
+               FLAC__uint64 nums[2] = { 3, 7 };
+               seekpoint_array[seekpoints++].sample_number = nums[0];
+               seekpoint_array[seekpoints++].sample_number = nums[1];
+               printf("testing FLAC__metadata_object_seekpoint_template_append_points()... ");
+               if(!FLAC__metadata_object_seektable_template_append_points(block, nums, sizeof(nums)/sizeof(FLAC__uint64))) {
+                       printf("FAILED, returned false\n");
+                       return false;
+               }
+               if(!check_seektable_(block, seekpoints, seekpoint_array))
+                       return false;
+       }
+
+       seekpoint_array[seekpoints++].sample_number = 0;
+       seekpoint_array[seekpoints++].sample_number = 10;
+       seekpoint_array[seekpoints++].sample_number = 20;
+       printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points()... ");
+       if(!FLAC__metadata_object_seektable_template_append_spaced_points(block, 3, 30)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoints--;
+       seekpoint_array[0].sample_number = 0;
+       seekpoint_array[1].sample_number = 3;
+       seekpoint_array[2].sample_number = 7;
+       seekpoint_array[3].sample_number = 10;
+       seekpoint_array[4].sample_number = 20;
+       seekpoint_array[5].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+       seekpoint_array[6].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+       printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=true)... ");
+       if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!FLAC__metadata_object_seektable_is_legal(block)) {
+               printf("FAILED, seek table is illegal\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=false)... ");
+       if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!FLAC__metadata_object_seektable_is_legal(block)) {
+               printf("FAILED, seek table is illegal\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[seekpoints++].sample_number = 0;
+       seekpoint_array[seekpoints++].sample_number = 10;
+       seekpoint_array[seekpoints++].sample_number = 20;
+       printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+       if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 10, 30)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       seekpoint_array[seekpoints++].sample_number = 0;
+       seekpoint_array[seekpoints++].sample_number = 11;
+       seekpoint_array[seekpoints++].sample_number = 22;
+       printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+       if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 11, 30)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!check_seektable_(block, seekpoints, seekpoint_array))
+               return false;
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing VORBIS_COMMENT\n");
+
+       {
+               FLAC__StreamMetadata_VorbisComment_Entry entry_;
+               char *field_name, *field_value;
+
+               printf("testing FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()... ");
+               if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry_, "name", "value")) {
+                       printf("FAILED, returned false\n");
+                       return false;
+               }
+               if(strcmp((const char *)entry_.entry, "name=value")) {
+                       printf("FAILED, field mismatch\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               printf("testing FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()... ");
+               if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry_, &field_name, &field_value)) {
+                       printf("FAILED, returned false\n");
+                       return false;
+               }
+               if(strcmp(field_name, "name")) {
+                       printf("FAILED, field name mismatch\n");
+                       return false;
+               }
+               if(strcmp(field_value, "value")) {
+                       printf("FAILED, field value mismatch\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+               if(!FLAC__metadata_object_vorbiscomment_entry_matches(entry_, field_name, strlen(field_name))) {
+                       printf("FAILED, expected true, returned false\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+               if(FLAC__metadata_object_vorbiscomment_entry_matches(entry_, "blah", strlen("blah"))) {
+                       printf("FAILED, expected false, returned true\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               free(entry_.entry);
+               free(field_name);
+               free(field_value);
+       }
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8);
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       vorbiscomment = FLAC__metadata_object_clone(block);
+       if(0 == vorbiscomment) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       vc_resize_(vorbiscomment, 2);
+       printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(grow to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+       if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       vc_resize_(vorbiscomment, 1);
+       printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+       if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       vc_resize_(vorbiscomment, 0);
+       printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+       if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       vc_resize_(vorbiscomment, 0);
+       printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+       if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on beginning of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on middle of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name3")) != 1) {
+               printf("FAILED, expected 1, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 4) {
+               printf("FAILED, expected 4, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 5) {
+               printf("FAILED, expected 5, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name2")) != 0) {
+               printf("FAILED, expected 0, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name2")) != -1) {
+               printf("FAILED, expected -1, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+       if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "blah")) != -1) {
+               printf("FAILED, expected -1, got %d\n", j);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, copy)...");
+       vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       if(block->data.vorbis_comment.num_comments != 6) {
+               printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, copy)...");
+       vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       if(block->data.vorbis_comment.num_comments != 4) {
+               printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+       vc_delete_(vorbiscomment, 2);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+       vc_delete_(vorbiscomment, 2);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+       vc_delete_(vorbiscomment, 0);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 1, "rem0=val0");
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 2, "rem0=val1");
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 3, "rem0=val2");
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"blah\")...");
+       if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "blah")) != 0) {
+               printf("FAILED, expected 0, got %d\n", j);
+               return false;
+       }
+       if(block->data.vorbis_comment.num_comments != 4) {
+               printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"rem0\")...");
+       vc_delete_(vorbiscomment, 1);
+       if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "rem0")) != 1) {
+               printf("FAILED, expected 1, got %d\n", j);
+               return false;
+       }
+       if(block->data.vorbis_comment.num_comments != 3) {
+               printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"blah\")...");
+       if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "blah")) != 0) {
+               printf("FAILED, expected 0, got %d\n", j);
+               return false;
+       }
+       if(block->data.vorbis_comment.num_comments != 3) {
+               printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"rem0\")...");
+       vc_delete_(vorbiscomment, 1);
+       vc_delete_(vorbiscomment, 1);
+       if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "rem0")) != 2) {
+               printf("FAILED, expected 2, got %d\n", j);
+               return false;
+       }
+       if(block->data.vorbis_comment.num_comments != 1) {
+               printf("FAILED, expected 1 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_set_comment(copy)...");
+       vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+       FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/true);
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(copy)...");
+       vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+       FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/true);
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(vorbiscomment);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       vorbiscomment = FLAC__metadata_object_clone(block);
+       if(0 == vorbiscomment) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(vorbiscomment);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       vorbiscomment = FLAC__metadata_object_clone(block);
+       if(0 == vorbiscomment) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on beginning of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on middle of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+       vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, own)...");
+       vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       if(block->data.vorbis_comment.num_comments != 6) {
+               printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, own)...");
+       vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+       entry_clone_(&entry);
+       if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       if(block->data.vorbis_comment.num_comments != 4) {
+               printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+       vc_delete_(vorbiscomment, 2);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+       vc_delete_(vorbiscomment, 2);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+       vc_delete_(vorbiscomment, 0);
+       if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_set_comment(own)...");
+       vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+       entry_clone_(&entry);
+       FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/false);
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(own)...");
+       vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+       entry_clone_(&entry);
+       FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/false);
+       if(!mutils__compare_block(vorbiscomment, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(vorbiscomment);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing CUESHEET\n");
+
+       {
+               FLAC__StreamMetadata_CueSheet_Track *track_, *trackcopy_;
+
+               printf("testing FLAC__metadata_object_cuesheet_track_new()... ");
+               track_ = FLAC__metadata_object_cuesheet_track_new();
+               if(0 == track_) {
+                       printf("FAILED, returned NULL\n");
+                       return false;
+               }
+               printf("OK\n");
+
+               printf("testing FLAC__metadata_object_cuesheet_track_clone()... ");
+               trackcopy_ = FLAC__metadata_object_cuesheet_track_clone(track_);
+               if(0 == trackcopy_) {
+                       printf("FAILED, returned NULL\n");
+                       return false;
+               }
+               if(!compare_track_(trackcopy_, track_))
+                       return false;
+               printf("OK\n");
+
+               printf("testing FLAC__metadata_object_cuesheet_track_delete()... ");
+               FLAC__metadata_object_cuesheet_track_delete(trackcopy_);
+               FLAC__metadata_object_cuesheet_track_delete(track_);
+               printf("OK\n");
+       }
+
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = (
+               FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+               FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+       ) / 8;
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       cuesheet = FLAC__metadata_object_clone(block);
+       if(0 == cuesheet) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       cs_resize_(cuesheet, 2);
+       printf("testing FLAC__metadata_object_cuesheet_resize_tracks(grow to %u)...", cuesheet->data.cue_sheet.num_tracks);
+       if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       cs_resize_(cuesheet, 1);
+       printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+       if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       cs_resize_(cuesheet, 0);
+       printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+       if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on empty array...");
+       cs_insert_new_(&track, cuesheet, 0, 0, 1, "ABCDE1234567", false, false);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on beginning of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 0, 10, 2, "BBCDE1234567", false, false);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on middle of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 1, 20, 3, "CBCDE1234567", false, false);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on end of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 3, 30, 4, "DBCDE1234567", false, false);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_blank_track() on end of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 4, 0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0", false, false);
+       if(!FLAC__metadata_object_cuesheet_insert_blank_track(block, 4)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+       cs_delete_(cuesheet, 4);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 4)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+       cs_delete_(cuesheet, 2);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+       cs_delete_(cuesheet, 2);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+       cs_delete_(cuesheet, 0);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_set_track(copy)...");
+       cs_set_new_(&track, cuesheet, 0, 40, 5, "EBCDE1234567", false, false);
+       FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/true);
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       tr_resize_(cuesheet, 0, 2);
+       printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(grow to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+       if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       tr_resize_(cuesheet, 0, 1);
+       printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+       if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       tr_resize_(cuesheet, 0, 0);
+       printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+       if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       index.offset = 0;
+       index.number = 1;
+       printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on empty array...");
+       tr_insert_new_(cuesheet, 0, 0, index);
+       if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, index)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       index.offset = 10;
+       index.number = 2;
+       printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on beginning of non-empty array...");
+       tr_insert_new_(cuesheet, 0, 0, index);
+       if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, index)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       index.offset = 20;
+       index.number = 3;
+       printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on middle of non-empty array...");
+       tr_insert_new_(cuesheet, 0, 1, index);
+       if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 1, index)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       index.offset = 30;
+       index.number = 4;
+       printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on end of non-empty array...");
+       tr_insert_new_(cuesheet, 0, 3, index);
+       if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 3, index)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       index.offset = 0;
+       index.number = 0;
+       printf("testing FLAC__metadata_object_cuesheet_track_insert_blank_index() on end of non-empty array...");
+       tr_insert_new_(cuesheet, 0, 4, index);
+       if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(block, 0, 4)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+       tr_delete_(cuesheet, 0, 4);
+       if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 4)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on middle of array...");
+       tr_delete_(cuesheet, 0, 2);
+       if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+       tr_delete_(cuesheet, 0, 2);
+       if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on beginning of array...");
+       tr_delete_(cuesheet, 0, 0);
+       if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(cuesheet);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       cuesheet = FLAC__metadata_object_clone(block);
+       if(0 == cuesheet) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on empty array...");
+       cs_insert_new_(&track, cuesheet, 0, 60, 7, "GBCDE1234567", false, false);
+       track_clone_(&track);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on beginning of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 0, 70, 8, "HBCDE1234567", false, false);
+       track_clone_(&track);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on middle of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 1, 80, 9, "IBCDE1234567", false, false);
+       track_clone_(&track);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on end of non-empty array...");
+       cs_insert_new_(&track, cuesheet, 3, 90, 10, "JBCDE1234567", false, false);
+       track_clone_(&track);
+       if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+       cs_delete_(cuesheet, 2);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+       cs_delete_(cuesheet, 2);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+       cs_delete_(cuesheet, 0);
+       if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_set_track(own)...");
+       cs_set_new_(&track, cuesheet, 0, 100, 11, "KBCDE1234567", false, false);
+       track_clone_(&track);
+       FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/false);
+       if(!mutils__compare_block(cuesheet, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_cuesheet_is_legal()...");
+       {
+               const char *violation;
+               if(FLAC__metadata_object_cuesheet_is_legal(block, /*check_cd_da_subset=*/true, &violation)) {
+                       printf("FAILED, returned true when expecting false\n");
+                       return false;
+               }
+               printf("returned false as expected, violation=\"%s\" OK\n", violation);
+       }
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(cuesheet);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       printf("testing PICTURE\n");
+
+       printf("testing FLAC__metadata_object_new()... ");
+       block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
+       if(0 == block) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       expected_length = (
+               FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+               FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+               FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+               FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN
+       ) / 8;
+       if(block->length != expected_length) {
+               printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+               return false;
+       }
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       picture = FLAC__metadata_object_clone(block);
+       if(0 == picture) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       pi_set_mime_type(picture, "image/png\t");
+       printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+       if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned true when expecting false\n");
+                       return false;
+               }
+               printf("returned false as expected, violation=\"%s\" OK\n", violation);
+       }
+
+       pi_set_mime_type(picture, "image/png");
+       printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+       if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned false, violation=\"%s\"\n", violation);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+       printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+       if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned true when expecting false\n");
+                       return false;
+               }
+               printf("returned false as expected, violation=\"%s\" OK\n", violation);
+       }
+
+       pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+       printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+       if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION", /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned false, violation=\"%s\"\n", violation);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+
+       pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+       printf("testing FLAC__metadata_object_picture_set_data(copy)...");
+       if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       pi_set_mime_type(picture, "image/png\t");
+       printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+       if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned true when expecting false\n");
+                       return false;
+               }
+               printf("returned false as expected, violation=\"%s\" OK\n", violation);
+       }
+
+       pi_set_mime_type(picture, "image/png");
+       printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+       if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned false, violation=\"%s\"\n", violation);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+       printf("testing FLAC__metadata_object_picture_set_description(own)...");
+       if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned true when expecting false\n");
+                       return false;
+               }
+               printf("returned false as expected, violation=\"%s\" OK\n", violation);
+       }
+
+       pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+       printf("testing FLAC__metadata_object_picture_set_description(own)...");
+       if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_picture_is_legal()...");
+       {
+               const char *violation;
+               if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+                       printf("FAILED, returned false, violation=\"%s\"\n", violation);
+                       return false;
+               }
+               printf("OK\n");
+       }
+
+       pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+       printf("testing FLAC__metadata_object_picture_set_data(own)...");
+       if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) {
+               printf("FAILED, returned false\n");
+               return false;
+       }
+       if(!mutils__compare_block(picture, block))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_clone()... ");
+       blockcopy = FLAC__metadata_object_clone(block);
+       if(0 == blockcopy) {
+               printf("FAILED, returned NULL\n");
+               return false;
+       }
+       if(!mutils__compare_block(block, blockcopy))
+               return false;
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(blockcopy);
+       printf("OK\n");
+
+       printf("testing FLAC__metadata_object_delete()... ");
+       FLAC__metadata_object_delete(picture);
+       FLAC__metadata_object_delete(block);
+       printf("OK\n");
+
+
+       return true;
+}
diff --git a/src/test_libFLAC/test_libFLAC.dsp b/src/test_libFLAC/test_libFLAC.dsp
new file mode 100644 (file)
index 0000000..680c5d6
--- /dev/null
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="test_libFLAC" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_libFLAC - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libFLAC.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libFLAC.mak" CFG="test_libFLAC - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_libFLAC - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_libFLAC - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_libFLAC - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libFLAC\include" /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\obj\release\lib\test_libs_common_static.lib ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_libFLAC - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libFLAC\include" /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\grabbag_static.lib ..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\obj\debug\lib\test_libs_common_static.lib ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_libFLAC - Win32 Release"\r
+# Name "test_libFLAC - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\bitwriter.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\decoders.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encoders.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\format.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_manip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_object.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\bitwriter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\decoders.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encoders.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\format.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_libFLAC/test_libFLAC.vcproj b/src/test_libFLAC/test_libFLAC.vcproj
new file mode 100644 (file)
index 0000000..60a8c82
--- /dev/null
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_libFLAC"\r
+       ProjectGUID="{4cefbc8c-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_libFLAC"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\libFLAC\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\libFLAC\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\bitwriter.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\decoders.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encoders.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\format.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\bitwriter.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\decoders.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\encoders.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\format.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_manip.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_object.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_libs_common/Makefile.am b/src/test_libs_common/Makefile.am
new file mode 100644 (file)
index 0000000..f363f8b
--- /dev/null
@@ -0,0 +1,30 @@
+#  test_libs_common - Common code to library unit tests
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libtest_libs_common.la
+
+libtest_libs_common_la_SOURCES = \
+       file_utils_flac.c \
+       metadata_utils.c
+
+EXTRA_DIST = \
+       Makefile.lite \
+       README \
+       test_libs_common_static.dsp \
+       test_libs_common_static.vcproj
diff --git a/src/test_libs_common/Makefile.lite b/src/test_libs_common/Makefile.lite
new file mode 100644 (file)
index 0000000..fe7c92f
--- /dev/null
@@ -0,0 +1,35 @@
+#  test_libs_common - Common code to library unit tests
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+LIB_NAME = libtest_libs_common
+
+INCLUDES = -I$(topdir)/include
+
+SRCS_C = \
+       file_utils_flac.c \
+       metadata_utils.c
+
+include $(topdir)/build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_libs_common/README b/src/test_libs_common/README
new file mode 100644 (file)
index 0000000..6a704c2
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains a convenience library of routines that are
+common to the library unit testers.
diff --git a/src/test_libs_common/file_utils_flac.c b/src/test_libs_common/file_utils_flac.c
new file mode 100644 (file)
index 0000000..a52fee0
--- /dev/null
@@ -0,0 +1,153 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "test_libs_common/file_utils_flac.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h> /* for stat() */
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+const long file_utils__ogg_serial_number = 12345;
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = fwrite(ptr, size, nmemb, stream);
+       if(!ferror(stream))
+               fflush(stream);
+       return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+typedef struct {
+       FILE *file;
+} encoder_client_struct;
+
+static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t 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(local__fwrite(buffer, 1, bytes, ecd->file) != bytes)
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+       else
+               return FLAC__STREAM_ENCODER_WRITE_STATUS_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__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, off_t *output_filesize, unsigned length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, unsigned num_metadata)
+{
+       FLAC__int32 samples[1024];
+       FLAC__StreamEncoder *encoder;
+       FLAC__StreamEncoderInitStatus init_status;
+       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_ogg_serial_number(encoder, file_utils__ogg_serial_number);
+       FLAC__stream_encoder_set_verify(encoder, true);
+       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);
+
+       if(is_ogg)
+               init_status = FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+       else
+               init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+
+       if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_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;
+       }
+
+       (void)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 = filestats.st_size;
+       }
+
+       return true;
+}
diff --git a/src/test_libs_common/metadata_utils.c b/src/test_libs_common/metadata_utils.c
new file mode 100644 (file)
index 0000000..fe192e7
--- /dev/null
@@ -0,0 +1,657 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007  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.
+ */
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy)
+{
+       if(blockcopy->min_blocksize != block->min_blocksize) {
+               printf("FAILED, min_blocksize mismatch, expected %u, got %u\n", block->min_blocksize, blockcopy->min_blocksize);
+               return false;
+       }
+       if(blockcopy->max_blocksize != block->max_blocksize) {
+               printf("FAILED, max_blocksize mismatch, expected %u, got %u\n", block->max_blocksize, blockcopy->max_blocksize);
+               return false;
+       }
+       if(blockcopy->min_framesize != block->min_framesize) {
+               printf("FAILED, min_framesize mismatch, expected %u, got %u\n", block->min_framesize, blockcopy->min_framesize);
+               return false;
+       }
+       if(blockcopy->max_framesize != block->max_framesize) {
+               printf("FAILED, max_framesize mismatch, expected %u, got %u\n", block->max_framesize, blockcopy->max_framesize);
+               return false;
+       }
+       if(blockcopy->sample_rate != block->sample_rate) {
+               printf("FAILED, sample_rate mismatch, expected %u, got %u\n", block->sample_rate, blockcopy->sample_rate);
+               return false;
+       }
+       if(blockcopy->channels != block->channels) {
+               printf("FAILED, channels mismatch, expected %u, got %u\n", block->channels, blockcopy->channels);
+               return false;
+       }
+       if(blockcopy->bits_per_sample != block->bits_per_sample) {
+               printf("FAILED, bits_per_sample mismatch, expected %u, got %u\n", block->bits_per_sample, blockcopy->bits_per_sample);
+               return false;
+       }
+       if(blockcopy->total_samples != block->total_samples) {
+#ifdef _MSC_VER
+               printf("FAILED, total_samples mismatch, expected %I64u, got %I64u\n", block->total_samples, blockcopy->total_samples);
+#else
+               printf("FAILED, total_samples mismatch, expected %llu, got %llu\n", (unsigned long long)block->total_samples, (unsigned long long)blockcopy->total_samples);
+#endif
+               return false;
+       }
+       if(0 != memcmp(blockcopy->md5sum, block->md5sum, sizeof(block->md5sum))) {
+               printf("FAILED, md5sum mismatch, expected %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X, got %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+                       (unsigned)block->md5sum[0],
+                       (unsigned)block->md5sum[1],
+                       (unsigned)block->md5sum[2],
+                       (unsigned)block->md5sum[3],
+                       (unsigned)block->md5sum[4],
+                       (unsigned)block->md5sum[5],
+                       (unsigned)block->md5sum[6],
+                       (unsigned)block->md5sum[7],
+                       (unsigned)block->md5sum[8],
+                       (unsigned)block->md5sum[9],
+                       (unsigned)block->md5sum[10],
+                       (unsigned)block->md5sum[11],
+                       (unsigned)block->md5sum[12],
+                       (unsigned)block->md5sum[13],
+                       (unsigned)block->md5sum[14],
+                       (unsigned)block->md5sum[15],
+                       (unsigned)blockcopy->md5sum[0],
+                       (unsigned)blockcopy->md5sum[1],
+                       (unsigned)blockcopy->md5sum[2],
+                       (unsigned)blockcopy->md5sum[3],
+                       (unsigned)blockcopy->md5sum[4],
+                       (unsigned)blockcopy->md5sum[5],
+                       (unsigned)blockcopy->md5sum[6],
+                       (unsigned)blockcopy->md5sum[7],
+                       (unsigned)blockcopy->md5sum[8],
+                       (unsigned)blockcopy->md5sum[9],
+                       (unsigned)blockcopy->md5sum[10],
+                       (unsigned)blockcopy->md5sum[11],
+                       (unsigned)blockcopy->md5sum[12],
+                       (unsigned)blockcopy->md5sum[13],
+                       (unsigned)blockcopy->md5sum[14],
+                       (unsigned)blockcopy->md5sum[15]
+               );
+               return false;
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, unsigned block_length)
+{
+       /* we don't compare the padding guts */
+       (void)block, (void)blockcopy, (void)block_length;
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, unsigned block_length)
+{
+       if(block_length < sizeof(block->id)) {
+               printf("FAILED, bad block length = %u\n", block_length);
+               return false;
+       }
+       if(0 != memcmp(blockcopy->id, block->id, sizeof(block->id))) {
+               printf("FAILED, id mismatch, expected %02X%02X%02X%02X, got %02X%02X%02X%02X\n",
+                       (unsigned)block->id[0],
+                       (unsigned)block->id[1],
+                       (unsigned)block->id[2],
+                       (unsigned)block->id[3],
+                       (unsigned)blockcopy->id[0],
+                       (unsigned)blockcopy->id[1],
+                       (unsigned)blockcopy->id[2],
+                       (unsigned)blockcopy->id[3]
+               );
+               return false;
+       }
+       if(0 == block->data || 0 == blockcopy->data) {
+               if(block->data != blockcopy->data) {
+                       printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+                       return false;
+               }
+               else if(block_length - sizeof(block->id) > 0) {
+                       printf("FAILED, data pointer is null but block length is not 0\n");
+                       return false;
+               }
+       }
+       else {
+               if(block_length - sizeof(block->id) == 0) {
+                       printf("FAILED, data pointer is not null but block length is 0\n");
+                       return false;
+               }
+               else if(0 != memcmp(blockcopy->data, block->data, block_length - sizeof(block->id))) {
+                       printf("FAILED, data mismatch\n");
+                       return false;
+               }
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy)
+{
+       unsigned i;
+       if(blockcopy->num_points != block->num_points) {
+               printf("FAILED, num_points mismatch, expected %u, got %u\n", block->num_points, blockcopy->num_points);
+               return false;
+       }
+       for(i = 0; i < block->num_points; i++) {
+               if(blockcopy->points[i].sample_number != block->points[i].sample_number) {
+#ifdef _MSC_VER
+                       printf("FAILED, points[%u].sample_number mismatch, expected %I64u, got %I64u\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number);
+#else
+                       printf("FAILED, points[%u].sample_number mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->points[i].sample_number, (unsigned long long)blockcopy->points[i].sample_number);
+#endif
+                       return false;
+               }
+               if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) {
+#ifdef _MSC_VER
+                       printf("FAILED, points[%u].stream_offset mismatch, expected %I64u, got %I64u\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset);
+#else
+                       printf("FAILED, points[%u].stream_offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->points[i].stream_offset, (unsigned long long)blockcopy->points[i].stream_offset);
+#endif
+                       return false;
+               }
+               if(blockcopy->points[i].frame_samples != block->points[i].frame_samples) {
+                       printf("FAILED, points[%u].frame_samples mismatch, expected %u, got %u\n", i, block->points[i].frame_samples, blockcopy->points[i].frame_samples);
+                       return false;
+               }
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy)
+{
+       unsigned i;
+       if(blockcopy->vendor_string.length != block->vendor_string.length) {
+               printf("FAILED, vendor_string.length mismatch, expected %u, got %u\n", block->vendor_string.length, blockcopy->vendor_string.length);
+               return false;
+       }
+       if(0 == block->vendor_string.entry || 0 == blockcopy->vendor_string.entry) {
+               if(block->vendor_string.entry != blockcopy->vendor_string.entry) {
+                       printf("FAILED, vendor_string.entry mismatch\n");
+                       return false;
+               }
+       }
+       else if(0 != memcmp(blockcopy->vendor_string.entry, block->vendor_string.entry, block->vendor_string.length)) {
+               printf("FAILED, vendor_string.entry mismatch\n");
+               return false;
+       }
+       if(blockcopy->num_comments != block->num_comments) {
+               printf("FAILED, num_comments mismatch, expected %u, got %u\n", block->num_comments, blockcopy->num_comments);
+               return false;
+       }
+       for(i = 0; i < block->num_comments; i++) {
+               if(blockcopy->comments[i].length != block->comments[i].length) {
+                       printf("FAILED, comments[%u].length mismatch, expected %u, got %u\n", i, block->comments[i].length, blockcopy->comments[i].length);
+                       return false;
+               }
+               if(0 == block->comments[i].entry || 0 == blockcopy->comments[i].entry) {
+                       if(block->comments[i].entry != blockcopy->comments[i].entry) {
+                               printf("FAILED, comments[%u].entry mismatch\n", i);
+                               return false;
+                       }
+               }
+               else {
+                       if(0 != memcmp(blockcopy->comments[i].entry, block->comments[i].entry, block->comments[i].length)) {
+                               printf("FAILED, comments[%u].entry mismatch\n", i);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy)
+{
+       unsigned i, j;
+
+       if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) {
+               printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number);
+               return false;
+       }
+       if(blockcopy->lead_in != block->lead_in) {
+#ifdef _MSC_VER
+               printf("FAILED, lead_in mismatch, expected %I64u, got %I64u\n", block->lead_in, blockcopy->lead_in);
+#else
+               printf("FAILED, lead_in mismatch, expected %llu, got %llu\n", (unsigned long long)block->lead_in, (unsigned long long)blockcopy->lead_in);
+#endif
+               return false;
+       }
+       if(blockcopy->is_cd != block->is_cd) {
+               printf("FAILED, is_cd mismatch, expected %u, got %u\n", (unsigned)block->is_cd, (unsigned)blockcopy->is_cd);
+               return false;
+       }
+       if(blockcopy->num_tracks != block->num_tracks) {
+               printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks);
+               return false;
+       }
+       for(i = 0; i < block->num_tracks; i++) {
+               if(blockcopy->tracks[i].offset != block->tracks[i].offset) {
+#ifdef _MSC_VER
+                       printf("FAILED, tracks[%u].offset mismatch, expected %I64u, got %I64u\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
+#else
+                       printf("FAILED, tracks[%u].offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->tracks[i].offset, (unsigned long long)blockcopy->tracks[i].offset);
+#endif
+                       return false;
+               }
+               if(blockcopy->tracks[i].number != block->tracks[i].number) {
+                       printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].number, (unsigned)blockcopy->tracks[i].number);
+                       return false;
+               }
+               if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) {
+                       printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].num_indices, (unsigned)blockcopy->tracks[i].num_indices);
+                       return false;
+               }
+               /* num_indices == 0 means lead-out track so only the track offset and number are valid */
+               if(block->tracks[i].num_indices > 0) {
+                       if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) {
+                               printf("FAILED, tracks[%u].isrc mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc);
+                               return false;
+                       }
+                       if(blockcopy->tracks[i].type != block->tracks[i].type) {
+                               printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].type, (unsigned)blockcopy->tracks[i].type);
+                               return false;
+                       }
+                       if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) {
+                               printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].pre_emphasis, (unsigned)blockcopy->tracks[i].pre_emphasis);
+                               return false;
+                       }
+                       if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) {
+                               if(block->tracks[i].indices != blockcopy->tracks[i].indices) {
+                                       printf("FAILED, tracks[%u].indices mismatch\n", i);
+                                       return false;
+                               }
+                       }
+                       else {
+                               for(j = 0; j < block->tracks[i].num_indices; j++) {
+                                       if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) {
+#ifdef _MSC_VER
+                                               printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %I64u, got %I64u\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
+#else
+                                               printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %llu, got %llu\n", i, j, (unsigned long long)block->tracks[i].indices[j].offset, (unsigned long long)blockcopy->tracks[i].indices[j].offset);
+#endif
+                                               return false;
+                                       }
+                                       if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) {
+                                               printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (unsigned)block->tracks[i].indices[j].number, (unsigned)blockcopy->tracks[i].indices[j].number);
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy)
+{
+       size_t len, lencopy;
+       if(blockcopy->type != block->type) {
+               printf("FAILED, type mismatch, expected %u, got %u\n", (unsigned)block->type, (unsigned)blockcopy->type);
+               return false;
+       }
+       len = strlen(block->mime_type);
+       lencopy = strlen(blockcopy->mime_type);
+       if(lencopy != len) {
+               printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+               return false;
+       }
+       if(strcmp(blockcopy->mime_type, block->mime_type)) {
+               printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type);
+               return false;
+       }
+       len = strlen((const char *)block->description);
+       lencopy = strlen((const char *)blockcopy->description);
+       if(lencopy != len) {
+               printf("FAILED, description length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+               return false;
+       }
+       if(strcmp((const char *)blockcopy->description, (const char *)block->description)) {
+               printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description);
+               return false;
+       }
+       if(blockcopy->width != block->width) {
+               printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width);
+               return false;
+       }
+       if(blockcopy->height != block->height) {
+               printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height);
+               return false;
+       }
+       if(blockcopy->depth != block->depth) {
+               printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth);
+               return false;
+       }
+       if(blockcopy->colors != block->colors) {
+               printf("FAILED, colors mismatch, expected %u, got %u\n", block->colors, blockcopy->colors);
+               return false;
+       }
+       if(blockcopy->data_length != block->data_length) {
+               printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length);
+               return false;
+       }
+       if(memcmp(blockcopy->data, block->data, block->data_length)) {
+               printf("FAILED, data mismatch\n");
+               return false;
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length)
+{
+       if(0 == block->data || 0 == blockcopy->data) {
+               if(block->data != blockcopy->data) {
+                       printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+                       return false;
+               }
+               else if(block_length > 0) {
+                       printf("FAILED, data pointer is null but block length is not 0\n");
+                       return false;
+               }
+       }
+       else {
+               if(block_length == 0) {
+                       printf("FAILED, data pointer is not null but block length is 0\n");
+                       return false;
+               }
+               else if(0 != memcmp(blockcopy->data, block->data, block_length)) {
+                       printf("FAILED, data mismatch\n");
+                       return false;
+               }
+       }
+       return true;
+}
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy)
+{
+       if(blockcopy->type != block->type) {
+               printf("FAILED, type mismatch, expected %s, got %s\n", FLAC__MetadataTypeString[block->type], FLAC__MetadataTypeString[blockcopy->type]);
+               return false;
+       }
+       if(blockcopy->is_last != block->is_last) {
+               printf("FAILED, is_last mismatch, expected %u, got %u\n", (unsigned)block->is_last, (unsigned)blockcopy->is_last);
+               return false;
+       }
+       if(blockcopy->length != block->length) {
+               printf("FAILED, length mismatch, expected %u, got %u\n", block->length, blockcopy->length);
+               return false;
+       }
+       switch(block->type) {
+               case FLAC__METADATA_TYPE_STREAMINFO:
+                       return mutils__compare_block_data_streaminfo(&block->data.stream_info, &blockcopy->data.stream_info);
+               case FLAC__METADATA_TYPE_PADDING:
+                       return mutils__compare_block_data_padding(&block->data.padding, &blockcopy->data.padding, block->length);
+               case FLAC__METADATA_TYPE_APPLICATION:
+                       return mutils__compare_block_data_application(&block->data.application, &blockcopy->data.application, block->length);
+               case FLAC__METADATA_TYPE_SEEKTABLE:
+                       return mutils__compare_block_data_seektable(&block->data.seek_table, &blockcopy->data.seek_table);
+               case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                       return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
+               case FLAC__METADATA_TYPE_CUESHEET:
+                       return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
+               case FLAC__METADATA_TYPE_PICTURE:
+                       return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture);
+               default:
+                       return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length);
+       }
+}
+
+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 *calloc_or_die_(size_t n, size_t size)
+{
+       void *x = calloc(n, size);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)n * (unsigned)size);
+               exit(1);
+       }
+       return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+       char *x = strdup(s);
+       if(0 == x) {
+               fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+               exit(1);
+       }
+       return x;
+}
+
+void mutils__init_metadata_blocks(
+       FLAC__StreamMetadata *streaminfo,
+       FLAC__StreamMetadata *padding,
+       FLAC__StreamMetadata *seektable,
+       FLAC__StreamMetadata *application1,
+       FLAC__StreamMetadata *application2,
+       FLAC__StreamMetadata *vorbiscomment,
+       FLAC__StreamMetadata *cuesheet,
+       FLAC__StreamMetadata *picture,
+       FLAC__StreamMetadata *unknown
+)
+{
+       /*
+               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;
+
+       {
+               const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+               vorbiscomment->is_last = false;
+               vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
+               vorbiscomment->data.vorbis_comment.vendor_string.length = vendor_string_length;
+               vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+               memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+               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+1);
+               memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
+               vorbiscomment->data.vorbis_comment.comments[1].length = 0;
+               vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
+       }
+
+       cuesheet->is_last = false;
+       cuesheet->type = FLAC__METADATA_TYPE_CUESHEET;
+       cuesheet->length =
+               /* cuesheet guts */
+               (
+                       FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+               ) / 8 +
+               /* 2 tracks */
+               3 * (
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+               ) / 8 +
+               /* 3 index points */
+               3 * (
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+                       FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+               ) / 8
+       ;
+       memset(cuesheet->data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+       cuesheet->data.cue_sheet.media_catalog_number[0] = 'j';
+       cuesheet->data.cue_sheet.media_catalog_number[1] = 'C';
+       cuesheet->data.cue_sheet.lead_in = 2 * 44100;
+       cuesheet->data.cue_sheet.is_cd = true;
+       cuesheet->data.cue_sheet.num_tracks = 3;
+       cuesheet->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc_or_die_(cuesheet->data.cue_sheet.num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+       cuesheet->data.cue_sheet.tracks[0].offset = 0;
+       cuesheet->data.cue_sheet.tracks[0].number = 1;
+       memcpy(cuesheet->data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet->data.cue_sheet.tracks[0].isrc));
+       cuesheet->data.cue_sheet.tracks[0].type = 0;
+       cuesheet->data.cue_sheet.tracks[0].pre_emphasis = 1;
+       cuesheet->data.cue_sheet.tracks[0].num_indices = 2;
+       cuesheet->data.cue_sheet.tracks[0].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet->data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+       cuesheet->data.cue_sheet.tracks[0].indices[0].offset = 0;
+       cuesheet->data.cue_sheet.tracks[0].indices[0].number = 0;
+       cuesheet->data.cue_sheet.tracks[0].indices[1].offset = 123 * 588;
+       cuesheet->data.cue_sheet.tracks[0].indices[1].number = 1;
+       cuesheet->data.cue_sheet.tracks[1].offset = 1234 * 588;
+       cuesheet->data.cue_sheet.tracks[1].number = 2;
+       memcpy(cuesheet->data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet->data.cue_sheet.tracks[1].isrc));
+       cuesheet->data.cue_sheet.tracks[1].type = 1;
+       cuesheet->data.cue_sheet.tracks[1].pre_emphasis = 0;
+       cuesheet->data.cue_sheet.tracks[1].num_indices = 1;
+       cuesheet->data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet->data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+       cuesheet->data.cue_sheet.tracks[1].indices[0].offset = 0;
+       cuesheet->data.cue_sheet.tracks[1].indices[0].number = 1;
+       cuesheet->data.cue_sheet.tracks[2].offset = 12345 * 588;
+       cuesheet->data.cue_sheet.tracks[2].number = 170;
+       cuesheet->data.cue_sheet.tracks[2].num_indices = 0;
+
+       picture->is_last = false;
+       picture->type = FLAC__METADATA_TYPE_PICTURE;
+       picture->length =
+               (
+                       FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+                       FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+                       FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+                       FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+               ) / 8
+       ;
+       picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+       picture->data.picture.mime_type = strdup_or_die_("image/jpeg");
+       picture->length += strlen(picture->data.picture.mime_type);
+       picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+       picture->length += strlen((const char *)picture->data.picture.description);
+       picture->data.picture.width = 300;
+       picture->data.picture.height = 300;
+       picture->data.picture.depth = 24;
+       picture->data.picture.colors = 0;
+       picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+       picture->data.picture.data_length = strlen((const char *)picture->data.picture.data);
+       picture->length += picture->data.picture.data_length;
+
+       unknown->is_last = true;
+       unknown->type = 126;
+       unknown->length = 8;
+       unknown->data.unknown.data = (FLAC__byte*)malloc_or_die_(unknown->length);
+       memcpy(unknown->data.unknown.data, "\xfe\xdc\xba\x98\xf0\xe1\xd2\xc3", unknown->length);
+}
+
+void mutils__free_metadata_blocks(
+       FLAC__StreamMetadata *streaminfo,
+       FLAC__StreamMetadata *padding,
+       FLAC__StreamMetadata *seektable,
+       FLAC__StreamMetadata *application1,
+       FLAC__StreamMetadata *application2,
+       FLAC__StreamMetadata *vorbiscomment,
+       FLAC__StreamMetadata *cuesheet,
+       FLAC__StreamMetadata *picture,
+       FLAC__StreamMetadata *unknown
+)
+{
+       (void)streaminfo, (void)padding, (void)application2;
+       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);
+       free(cuesheet->data.cue_sheet.tracks[0].indices);
+       free(cuesheet->data.cue_sheet.tracks[1].indices);
+       free(cuesheet->data.cue_sheet.tracks);
+       free(picture->data.picture.mime_type);
+       free(picture->data.picture.description);
+       free(picture->data.picture.data);
+       free(unknown->data.unknown.data);
+}
diff --git a/src/test_libs_common/test_libs_common_static.dsp b/src/test_libs_common/test_libs_common_static.dsp
new file mode 100644 (file)
index 0000000..b411fed
--- /dev/null
@@ -0,0 +1,108 @@
+# Microsoft Developer Studio Project File - Name="test_libs_common_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=test_libs_common_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libs_common_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_libs_common_static.mak" CFG="test_libs_common_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_libs_common_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "test_libs_common_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "test_libs_common"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_libs_common_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\lib"\r
+# PROP Intermediate_Dir "Release_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /Op /I ".\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ELSEIF  "$(CFG)" == "test_libs_common_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\lib"\r
+# PROP Intermediate_Dir "Debug_static"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_libs_common_static - Win32 Release"\r
+# Name "test_libs_common_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\file_utils_flac.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\metadata_utils.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Public Header Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\test_libs_common\file_utils_flac.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\include\test_libs_common\metadata_utils.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_libs_common/test_libs_common_static.vcproj b/src/test_libs_common/test_libs_common_static.vcproj
new file mode 100644 (file)
index 0000000..4e512ea
--- /dev/null
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_libs_common_static"\r
+       ProjectGUID="{4cefbc8e-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_libs_common_static"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\lib"\r
+                       IntermediateDirectory="Debug_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\obj\debug\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\lib"\r
+                       IntermediateDirectory="Release_static"\r
+                       ConfigurationType="4"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".\include;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile="..\..\..\obj\release\lib\$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\file_utils_flac.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\metadata_utils.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_seeking/Makefile.am b/src/test_seeking/Makefile.am
new file mode 100644 (file)
index 0000000..120e233
--- /dev/null
@@ -0,0 +1,34 @@
+#  test_seeking - Seeking tester for libFLAC
+#  Copyright (C) 2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_seeking.dsp \
+       test_seeking.vcproj
+
+AM_CFLAGS = @OGG_CFLAGS@
+
+INCLUDES = 
+
+noinst_PROGRAMS = test_seeking
+test_seeking_LDADD = \
+       $(top_builddir)/src/libFLAC/libFLAC.la \
+       @OGG_LIBS@ \
+       @MINGW_WINSOCK_LIBS@ \
+       -lm
+test_seeking_SOURCES = \
+       main.c
diff --git a/src/test_seeking/Makefile.lite b/src/test_seeking/Makefile.lite
new file mode 100644 (file)
index 0000000..0df91a0
--- /dev/null
@@ -0,0 +1,40 @@
+#  test_seeking - Seeking tester for libFLAC
+#  Copyright (C) 2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_seeking
+
+INCLUDES = -I../libFLAC/include -I$(topdir)/include
+
+ifeq ($(DARWIN_BUILD),yes)
+EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -lm
+else
+LIBS = -lFLAC -L$(OGG_LIB_DIR) -logg -lm
+endif
+
+SRCS_C = \
+       main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_seeking/main.c b/src/test_seeking/main.c
new file mode 100644 (file)
index 0000000..11b549a
--- /dev/null
@@ -0,0 +1,501 @@
+/* test_seeking - Seeking tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include <sys/stat.h> /* for stat() */
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+
+typedef struct {
+       FLAC__int32 **pcm;
+       FLAC__bool got_data;
+       FLAC__uint64 total_samples;
+       unsigned channels;
+       unsigned bits_per_sample;
+       FLAC__bool quiet;
+       FLAC__bool ignore_errors;
+       FLAC__bool error_occurred;
+} DecoderClientData;
+
+static FLAC__bool stop_signal_ = false;
+
+static void our_sigint_handler_(int signal)
+{
+       (void)signal;
+       printf("(caught SIGINT) ");
+       fflush(stdout);
+       stop_signal_ = true;
+}
+
+static FLAC__bool die_(const char *msg)
+{
+       printf("ERROR: %s\n", msg);
+       return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+       FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+       if(msg)
+               printf("FAILED, %s", msg);
+       else
+               printf("FAILED");
+
+       printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamDecoderStateString[state]);
+
+       return false;
+}
+
+static unsigned local_rand_(void)
+{
+#if !defined _MSC_VER && !defined __MINGW32__
+#define RNDFUNC random
+#else
+#define RNDFUNC rand
+#endif
+       /* every RAND_MAX I've ever seen is 2^15-1 or 2^31-1, so a little hackery here: */
+       if (RAND_MAX > 32767)
+               return RNDFUNC();
+       else /* usually MSVC, some solaris */
+               return (RNDFUNC()<<15) | RNDFUNC();
+#undef RNDFUNC
+}
+
+static off_t get_filesize_(const char *srcpath)
+{
+       struct stat srcstat;
+
+       if(0 == stat(srcpath, &srcstat))
+               return srcstat.st_size;
+       else
+               return -1;
+}
+
+static FLAC__bool read_pcm_(FLAC__int32 *pcm[], const char *rawfilename, const char *flacfilename)
+{
+       FILE *f;
+       unsigned channels = 0, bps = 0, samples, i, j;
+
+       off_t rawfilesize = get_filesize_(rawfilename);
+       if (rawfilesize < 0) {
+               fprintf(stderr, "ERROR: can't determine filesize for %s\n", rawfilename);
+               return false;
+       }
+       /* get sample format from flac file; would just use FLAC__metadata_get_streaminfo() except it doesn't work for Ogg FLAC yet */
+       {
+#if 0
+               FLAC__StreamMetadata streaminfo;
+               if(!FLAC__metadata_get_streaminfo(flacfilename, &streaminfo)) {
+                       printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+                       return false;
+               }
+               channels = streaminfo.data.stream_info.channels;
+               bps = streaminfo.data.stream_info.bits_per_sample;
+#else
+               FLAC__bool ok = true;
+               FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+               FLAC__Metadata_Iterator *it = 0;
+               ok = ok && chain && (FLAC__metadata_chain_read(chain, flacfilename) || FLAC__metadata_chain_read_ogg(chain, flacfilename));
+               ok = ok && (it = FLAC__metadata_iterator_new());
+               if(ok) FLAC__metadata_iterator_init(it, chain);
+               ok = ok && (FLAC__metadata_iterator_get_block(it)->type == FLAC__METADATA_TYPE_STREAMINFO);
+               ok = ok && (channels = FLAC__metadata_iterator_get_block(it)->data.stream_info.channels);
+               ok = ok && (bps = FLAC__metadata_iterator_get_block(it)->data.stream_info.bits_per_sample);
+               if(it) FLAC__metadata_iterator_delete(it);
+               if(chain) FLAC__metadata_chain_delete(chain);
+               if(!ok) {
+                       printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+                       return false;
+               }
+#endif
+       }
+       if(channels > 2) {
+               printf("ERROR: PCM verification requires 1 or 2 channels, got %u\n", channels);
+               return false;
+       }
+       if(bps != 8 && bps != 16) {
+               printf("ERROR: PCM verification requires 8 or 16 bps, got %u\n", bps);
+               return false;
+       }
+       samples = rawfilesize / channels / (bps>>3);
+       if (samples > 10000000) {
+               fprintf(stderr, "ERROR: %s is too big\n", rawfilename);
+               return false;
+       }
+       for(i = 0; i < channels; i++) {
+               if(0 == (pcm[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32)*samples))) {
+                       printf("ERROR: allocating space for PCM samples\n");
+                       return false;
+               }
+       }
+       if(0 == (f = fopen(rawfilename, "rb"))) {
+               printf("ERROR: opening %s for reading\n", rawfilename);
+               return false;
+       }
+       /* assumes signed big-endian data */
+       if(bps == 8) {
+               signed char c;
+               for(i = 0; i < samples; i++) {
+                       for(j = 0; j < channels; j++) {
+                               fread(&c, 1, 1, f);
+                               pcm[j][i] = c;
+                       }
+               }
+       }
+       else { /* bps == 16 */
+               unsigned char c[2];
+               for(i = 0; i < samples; i++) {
+                       for(j = 0; j < channels; j++) {
+                               fread(&c, 1, 2, f);
+                               pcm[j][i] = ((int)((signed char)c[0])) << 8 | (int)c[1];
+                       }
+               }
+       }
+       fclose(f);
+       return true;
+}
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+       (void)decoder, (void)buffer;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in write callback is NULL\n");
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+       }
+
+       if(dcd->error_occurred)
+               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+       FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); /* decoder guarantees this */
+       if (!dcd->quiet)
+#ifdef _MSC_VER
+               printf("frame@%I64u(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
+#else
+               printf("frame@%llu(%u)... ", (unsigned long long)frame->header.number.sample_number, frame->header.blocksize);
+#endif
+       fflush(stdout);
+
+       /* check against PCM data if we have it */
+       if (dcd->pcm) {
+               unsigned c, i, j;
+               for (c = 0; c < frame->header.channels; c++)
+                       for (i = (unsigned)frame->header.number.sample_number, j = 0; j < frame->header.blocksize; i++, j++)
+                               if (buffer[c][j] != dcd->pcm[c][i]) {
+                                       printf("ERROR: sample mismatch at sample#%u(%u), channel=%u, expected %d, got %d\n", i, j, c, buffer[c][j], dcd->pcm[c][i]);
+                                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+                               }
+       }
+
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in metadata callback is NULL\n");
+               return;
+       }
+
+       if(dcd->error_occurred)
+               return;
+
+       if (!dcd->got_data && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               dcd->got_data = true;
+               dcd->total_samples = metadata->data.stream_info.total_samples;
+               dcd->channels = metadata->data.stream_info.channels;
+               dcd->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+       }
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+       DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+       (void)decoder;
+
+       if(0 == dcd) {
+               printf("ERROR: client_data in error callback is NULL\n");
+               return;
+       }
+
+       if(!dcd->ignore_errors) {
+               printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
+               dcd->error_occurred = true;
+       }
+}
+
+/* read mode:
+ * 0 - no read after seek
+ * 1 - read 2 frames
+ * 2 - read until end
+ */
+static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t filesize, unsigned count, FLAC__int64 total_samples, unsigned read_mode, FLAC__int32 **pcm)
+{
+       FLAC__StreamDecoder *decoder;
+       DecoderClientData decoder_client_data;
+       unsigned i;
+       long int n;
+
+       decoder_client_data.pcm = pcm;
+       decoder_client_data.got_data = false;
+       decoder_client_data.total_samples = 0;
+       decoder_client_data.quiet = false;
+       decoder_client_data.ignore_errors = false;
+       decoder_client_data.error_occurred = false;
+
+       printf("\n+++ seek test: FLAC__StreamDecoder (%s FLAC, read_mode=%u)\n\n", is_ogg? "Ogg":"native", read_mode);
+
+       decoder = FLAC__stream_decoder_new();
+       if(0 == decoder)
+               return die_("FLAC__stream_decoder_new() FAILED, returned NULL\n");
+
+       if(is_ogg) {
+               if(FLAC__stream_decoder_init_ogg_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+                       return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+       }
+       else {
+               if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+                       return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+       }
+
+       if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+               return die_s_("FLAC__stream_decoder_process_until_end_of_metadata() FAILED", decoder);
+
+       if(!is_ogg) { /* not necessary to do this for Ogg because of its seeking method */
+       /* process until end of stream to make sure we can still seek in that state */
+               decoder_client_data.quiet = true;
+               if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+                       return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+               decoder_client_data.quiet = false;
+
+               printf("stream decoder state is %s\n", FLAC__stream_decoder_get_resolved_state_string(decoder));
+               if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
+                       return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder);
+       }
+
+#ifdef _MSC_VER
+       printf("file's total_samples is %I64u\n", decoder_client_data.total_samples);
+#else
+       printf("file's total_samples is %llu\n", (unsigned long long)decoder_client_data.total_samples);
+#endif
+       n = (long int)decoder_client_data.total_samples;
+
+       if(n == 0 && total_samples >= 0)
+               n = (long int)total_samples;
+
+       /* if we don't have a total samples count, just guess based on the file size */
+       /* @@@ for is_ogg we should get it from last page's granulepos */
+       if(n == 0) {
+               /* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */
+               n = 9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample);
+       }
+
+       printf("Begin seek barrage, count=%u\n", count);
+
+       for (i = 0; !stop_signal_ && (count == 0 || i < count); i++) {
+               FLAC__uint64 pos;
+
+               /* for the first 10, seek to the first 10 samples */
+               if (n >= 10 && i < 10) {
+                       pos = i;
+               }
+               /* for the second 10, seek to the last 10 samples */
+               else if (n >= 10 && i < 20) {
+                       pos = n - 1 - (i-10);
+               }
+               /* for the third 10, seek past the end and make sure we fail properly as expected */
+               else if (i < 30) {
+                       pos = n + (i-20);
+               }
+               else {
+                       pos = (FLAC__uint64)(local_rand_() % n);
+               }
+
+#ifdef _MSC_VER
+               printf("#%u:seek(%I64u)... ", i, pos);
+#else
+               printf("#%u:seek(%llu)... ", i, (unsigned long long)pos);
+#endif
+               fflush(stdout);
+               if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) {
+                       if(pos >= (FLAC__uint64)n)
+                               printf("seek past end failed as expected... ");
+                       else if(decoder_client_data.total_samples == 0 && total_samples <= 0)
+                               printf("seek failed, assuming it was past EOF... ");
+                       else
+                               return die_s_("FLAC__stream_decoder_seek_absolute() FAILED", decoder);
+                       if(!FLAC__stream_decoder_flush(decoder))
+                               return die_s_("FLAC__stream_decoder_flush() FAILED", decoder);
+               }
+               else if(read_mode == 1) {
+                       printf("decode_frame... ");
+                       fflush(stdout);
+                       if(!FLAC__stream_decoder_process_single(decoder))
+                               return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+
+                       printf("decode_frame... ");
+                       fflush(stdout);
+                       if(!FLAC__stream_decoder_process_single(decoder))
+                               return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+               }
+               else if(read_mode == 2) {
+                       printf("decode_all... ");
+                       fflush(stdout);
+                       decoder_client_data.quiet = true;
+                       if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+                               return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+                       decoder_client_data.quiet = false;
+               }
+
+               printf("OK\n");
+               fflush(stdout);
+       }
+       stop_signal_ = false;
+
+       if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) {
+               if(!FLAC__stream_decoder_finish(decoder))
+                       return die_s_("FLAC__stream_decoder_finish() FAILED", decoder);
+       }
+
+       FLAC__stream_decoder_delete(decoder);
+       printf("\nPASSED!\n");
+
+       return true;
+}
+
+#ifdef _MSC_VER
+/* There's no strtoull() in MSVC6 so we just write a specialized one */
+static FLAC__uint64 local__strtoull(const char *src)
+{
+       FLAC__uint64 ret = 0;
+       int c;
+       FLAC__ASSERT(0 != src);
+       while(0 != (c = *src++)) {
+               c -= '0';
+               if(c >= 0 && c <= 9)
+                       ret = (ret * 10) + c;
+               else
+                       break;
+       }
+       return ret;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+       const char *flacfilename, *rawfilename = 0;
+       unsigned count = 0, read_mode;
+       FLAC__int64 samples = -1;
+       off_t flacfilesize;
+       FLAC__int32 *pcm[2] = { 0, 0 };
+       FLAC__bool ok = true;
+
+       static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac] [file.raw]\n";
+
+       if (argc < 2 || argc > 5) {
+               fprintf(stderr, usage);
+               return 1;
+       }
+
+       flacfilename = argv[1];
+
+       if (argc > 2)
+               count = strtoul(argv[2], 0, 10);
+       if (argc > 3)
+#ifdef _MSC_VER
+               samples = local__strtoull(argv[3]);
+#else
+               samples = strtoull(argv[3], 0, 10);
+#endif
+       if (argc > 4)
+               rawfilename = argv[4];
+
+       if (count < 30)
+               fprintf(stderr, "WARNING: random seeks don't kick in until after 30 preprogrammed ones\n");
+
+#if !defined _MSC_VER && !defined __MINGW32__
+       {
+               struct timeval tv;
+
+               if (gettimeofday(&tv, 0) < 0) {
+                       fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+                       tv.tv_usec = 4321;
+               }
+               srandom(tv.tv_usec);
+       }
+#else
+       srand((unsigned)time(0));
+#endif
+
+       flacfilesize = get_filesize_(flacfilename);
+       if (flacfilesize < 0) {
+               fprintf(stderr, "ERROR: can't determine filesize for %s\n", flacfilename);
+               return 1;
+       }
+
+       if (rawfilename && !read_pcm_(pcm, rawfilename, flacfilename)) {
+               free(pcm[0]);
+               free(pcm[1]);
+               return 1;
+       }
+
+       (void) signal(SIGINT, our_sigint_handler_);
+
+       for (read_mode = 0; ok && read_mode <= 2; read_mode++) {
+               /* no need to do "decode all" read_mode if PCM checking is available */
+               if (rawfilename && read_mode > 1)
+                       continue;
+               if (strlen(flacfilename) > 4 && (0 == strcmp(flacfilename+strlen(flacfilename)-4, ".oga") || 0 == strcmp(flacfilename+strlen(flacfilename)-4, ".ogg"))) {
+#if FLAC__HAS_OGG
+                       ok = seek_barrage(/*is_ogg=*/true, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
+#else
+                       fprintf(stderr, "ERROR: Ogg FLAC not supported\n");
+                       ok = false;
+#endif
+               }
+               else {
+                       ok = seek_barrage(/*is_ogg=*/false, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
+               }
+       }
+
+       free(pcm[0]);
+       free(pcm[1]);
+
+       return ok? 0 : 2;
+}
diff --git a/src/test_seeking/test_seeking.dsp b/src/test_seeking/test_seeking.dsp
new file mode 100644 (file)
index 0000000..67318bf
--- /dev/null
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="test_seeking" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_seeking - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_seeking.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_seeking.mak" CFG="test_seeking - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_seeking - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_seeking - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_seeking - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_seeking - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_seeking - Win32 Release"\r
+# Name "test_seeking - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_seeking/test_seeking.vcproj b/src/test_seeking/test_seeking.vcproj
new file mode 100644 (file)
index 0000000..a799fde
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_seeking"\r
+       ProjectGUID="{4cefbc90-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_seeking"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/test_streams/Makefile.am b/src/test_streams/Makefile.am
new file mode 100644 (file)
index 0000000..2d562ce
--- /dev/null
@@ -0,0 +1,26 @@
+#  test_streams - Simple test pattern generator
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+
+EXTRA_DIST = \
+       Makefile.lite \
+       test_streams.dsp \
+       test_streams.vcproj
+
+noinst_PROGRAMS = test_streams
+test_streams_SOURCES = \
+       main.c
+test_streams_LDADD = -lm
diff --git a/src/test_streams/Makefile.lite b/src/test_streams/Makefile.lite
new file mode 100644 (file)
index 0000000..af9dab6
--- /dev/null
@@ -0,0 +1,36 @@
+#  test_streams - Simple test pattern generator
+#  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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
+#
+
+topdir = ../..
+libdir = $(topdir)/obj/$(BUILD)/lib
+
+PROGRAM_NAME = test_streams
+
+INCLUDES = -I./include -I$(topdir)/include
+
+LIBS = -lm
+
+SRCS_C = \
+       main.c
+
+include $(topdir)/build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_streams/main.c b/src/test_streams/main.c
new file mode 100644 (file)
index 0000000..c335776
--- /dev/null
@@ -0,0 +1,927 @@
+/* test_streams - Simple test pattern generator
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  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.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/ordinals.h"
+
+#ifndef M_PI
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_PI 3.14159265358979323846
+#endif
+
+#if !defined _MSC_VER && !defined __MINGW32__
+#define GET_RANDOM_BYTE (((unsigned)random()) & 0xff)
+#else
+#define GET_RANDOM_BYTE (((unsigned)rand()) & 0xff)
+#endif
+
+static FLAC__bool is_big_endian_host;
+
+
+static FLAC__bool write_little_endian(FILE *f, FLAC__int32 x, size_t bytes)
+{
+       while(bytes) {
+               if(fputc(x, f) == EOF)
+                       return false;
+               x >>= 8;
+               bytes--;
+       }
+       return true;
+}
+
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF
+       ;
+}
+
+static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+       return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static FLAC__bool write_little_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x >> 16, f) != EOF
+       ;
+}
+
+static FLAC__bool write_little_endian_int24(FILE *f, FLAC__int32 x)
+{
+       return write_little_endian_uint24(f, (FLAC__uint32)x);
+}
+
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x >> 16, f) != EOF &&
+               fputc(x >> 24, f) != EOF
+       ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x)
+{
+       return write_little_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_big_endian(FILE *f, FLAC__int32 x, size_t bytes)
+{
+       if(bytes < 4)
+               x <<= 8*(4-bytes);
+       while(bytes) {
+               if(fputc(x>>24, f) == EOF)
+                       return false;
+               x <<= 8;
+               bytes--;
+       }
+       return true;
+}
+
+static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+       return
+               fputc(x >> 8, f) != EOF &&
+               fputc(x, f) != EOF
+       ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int16(FILE *f, FLAC__int16 x)
+{
+       return write_big_endian_uint16(f, (FLAC__uint16)x);
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x >> 16, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x, f) != EOF
+       ;
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int24(FILE *f, FLAC__int32 x)
+{
+       return write_big_endian_uint24(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+       return
+               fputc(x >> 24, f) != EOF &&
+               fputc(x >> 16, f) != EOF &&
+               fputc(x >> 8, f) != EOF &&
+               fputc(x, f) != EOF
+       ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int32(FILE *f, FLAC__int32 x)
+{
+       return write_big_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_sane_extended(FILE *f, unsigned val)
+       /* Write to 'f' a SANE extended representation of 'val'.  Return false if
+       * the write succeeds; return true otherwise.
+       *
+       * SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits
+       * of exponent, and 64 bits of significand (mantissa).  Unlike most IEEE-754
+       * representations, it does not imply a 1 above the MSB of the significand.
+       *
+       * Preconditions:
+       *  val!=0U
+       */
+{
+       unsigned int shift, exponent;
+
+       FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */
+
+       for(shift= 0U; (val>>(31-shift))==0U; ++shift)
+               ;
+       val<<= shift;
+       exponent= 63U-(shift+32U); /* add 32 for unused second word */
+
+       if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF)))
+               return false;
+       if(!write_big_endian_uint32(f, val))
+               return false;
+       if(!write_big_endian_uint32(f, 0)) /* unused second word */
+               return false;
+
+       return true;
+}
+
+/* a mono one-sample 16bps stream */
+static FLAC__bool generate_01(void)
+{
+       FILE *f;
+       FLAC__int16 x = -32768;
+
+       if(0 == (f = fopen("test01.raw", "wb")))
+               return false;
+
+       if(!write_little_endian_int16(f, x))
+               goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo one-sample 16bps stream */
+static FLAC__bool generate_02(void)
+{
+       FILE *f;
+       FLAC__int16 xl = -32768, xr = 32767;
+
+       if(0 == (f = fopen("test02.raw", "wb")))
+               return false;
+
+       if(!write_little_endian_int16(f, xl))
+               goto foo;
+       if(!write_little_endian_int16(f, xr))
+               goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono five-sample 16bps stream */
+static FLAC__bool generate_03(void)
+{
+       FILE *f;
+       FLAC__int16 x[] = { -25, 0, 25, 50, 100 };
+       unsigned i;
+
+       if(0 == (f = fopen("test03.raw", "wb")))
+               return false;
+
+       for(i = 0; i < 5; i++)
+               if(!write_little_endian_int16(f, x[i]))
+                       goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo five-sample 16bps stream */
+static FLAC__bool generate_04(void)
+{
+       FILE *f;
+       FLAC__int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 };
+       unsigned i;
+
+       if(0 == (f = fopen("test04.raw", "wb")))
+               return false;
+
+       for(i = 0; i < 10; i++)
+               if(!write_little_endian_int16(f, x[i]))
+                       goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono full-scale deflection 8bps stream */
+static FLAC__bool generate_fsd8(const char *fn, const int pattern[], unsigned reps)
+{
+       FILE *f;
+       unsigned rep, p;
+
+       FLAC__ASSERT(pattern != 0);
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(rep = 0; rep < reps; rep++) {
+               for(p = 0; pattern[p]; p++) {
+                       signed char x = pattern[p] > 0? 127 : -128;
+                       if(fwrite(&x, sizeof(x), 1, f) < 1)
+                               goto foo;
+               }
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono full-scale deflection 16bps stream */
+static FLAC__bool generate_fsd16(const char *fn, const int pattern[], unsigned reps)
+{
+       FILE *f;
+       unsigned rep, p;
+
+       FLAC__ASSERT(pattern != 0);
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(rep = 0; rep < reps; rep++) {
+               for(p = 0; pattern[p]; p++) {
+                       FLAC__int16 x = pattern[p] > 0? 32767 : -32768;
+                       if(!write_little_endian_int16(f, x))
+                               goto foo;
+               }
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo wasted-bits-per-sample 16bps stream */
+static FLAC__bool generate_wbps16(const char *fn, unsigned samples)
+{
+       FILE *f;
+       unsigned sample;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(sample = 0; sample < samples; sample++) {
+               FLAC__int16 l = (sample % 2000) << 2;
+               FLAC__int16 r = (sample % 1000) << 3;
+               if(!write_little_endian_int16(f, l))
+                       goto foo;
+               if(!write_little_endian_int16(f, r))
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono full-scale deflection 24bps stream */
+static FLAC__bool generate_fsd24(const char *fn, const int pattern[], unsigned reps)
+{
+       FILE *f;
+       unsigned rep, p;
+
+       FLAC__ASSERT(pattern != 0);
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(rep = 0; rep < reps; rep++) {
+               for(p = 0; pattern[p]; p++) {
+                       FLAC__int32 x = pattern[p] > 0? 8388607 : -8388608;
+                       if(!write_little_endian_int24(f, x))
+                               goto foo;
+               }
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono sine-wave 8bps stream */
+static FLAC__bool generate_sine8_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+       const FLAC__int8 full_scale = 127;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int8 v = (FLAC__int8)(val + 0.5);
+               if(fwrite(&v, sizeof(v), 1, f) < 1)
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo sine-wave 8bps stream */
+static FLAC__bool generate_sine8_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+       const FLAC__int8 full_scale = 127;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int8 v = (FLAC__int8)(val + 0.5);
+               if(fwrite(&v, sizeof(v), 1, f) < 1)
+                       goto foo;
+               val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+               v = (FLAC__int8)(val + 0.5);
+               if(fwrite(&v, sizeof(v), 1, f) < 1)
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono sine-wave 16bps stream */
+static FLAC__bool generate_sine16_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+       const FLAC__int16 full_scale = 32767;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int16 v = (FLAC__int16)(val + 0.5);
+               if(!write_little_endian_int16(f, v))
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo sine-wave 16bps stream */
+static FLAC__bool generate_sine16_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+       const FLAC__int16 full_scale = 32767;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int16 v = (FLAC__int16)(val + 0.5);
+               if(!write_little_endian_int16(f, v))
+                       goto foo;
+               val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+               v = (FLAC__int16)(val + 0.5);
+               if(!write_little_endian_int16(f, v))
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a mono sine-wave 24bps stream */
+static FLAC__bool generate_sine24_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+       const FLAC__int32 full_scale = 0x7fffff;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int32 v = (FLAC__int32)(val + 0.5);
+               if(!write_little_endian_int24(f, v))
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+/* a stereo sine-wave 24bps stream */
+static FLAC__bool generate_sine24_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+       const FLAC__int32 full_scale = 0x7fffff;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       FILE *f;
+       double theta1, theta2;
+       unsigned i;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+               FLAC__int32 v = (FLAC__int32)(val + 0.5);
+               if(!write_little_endian_int24(f, v))
+                       goto foo;
+               val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+               v = (FLAC__int32)(val + 0.5);
+               if(!write_little_endian_int24(f, v))
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+static FLAC__bool generate_noise(const char *fn, unsigned bytes)
+{
+       FILE *f;
+       unsigned b;
+
+       if(0 == (f = fopen(fn, "wb")))
+               return false;
+
+       for(b = 0; b < bytes; b++) {
+#if !defined _MSC_VER && !defined __MINGW32__
+               FLAC__byte x = (FLAC__byte)(((unsigned)random()) & 0xff);
+#else
+               FLAC__byte x = (FLAC__byte)(((unsigned)rand()) & 0xff);
+#endif
+               if(fwrite(&x, sizeof(x), 1, f) < 1)
+                       goto foo;
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+static FLAC__bool generate_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples)
+{
+       const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1;
+       const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+       const double delta1 = 2.0 * M_PI / ( 44100.0 / f1);
+       const double delta2 = 2.0 * M_PI / ( 44100.0 / f2);
+       double theta1, theta2;
+       FILE *f;
+       unsigned i, j;
+
+       if(0 == (f = fopen(filename, "wb")))
+               return false;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               for(j = 0; j < channels; j++) {
+                       double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+                       FLAC__int32 v = (FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8);
+                       if(!write_little_endian(f, v, bytes_per_sample))
+                               goto foo;
+               }
+       }
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples)
+{
+       const unsigned bytes_per_sample = (bps+7)/8;
+       const unsigned true_size = channels * bytes_per_sample * samples;
+       const unsigned padded_size = (true_size + 1) & (~1u);
+       const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+       const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+       const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       double theta1, theta2;
+       FILE *f;
+       unsigned i, j;
+
+       if(0 == (f = fopen(filename, "wb")))
+               return false;
+       if(fwrite("FORM", 1, 4, f) < 4)
+               goto foo;
+       if(!write_big_endian_uint32(f, padded_size + 46))
+               goto foo;
+       if(fwrite("AIFFCOMM\000\000\000\022", 1, 12, f) < 12)
+               goto foo;
+       if(!write_big_endian_uint16(f, (FLAC__uint16)channels))
+               goto foo;
+       if(!write_big_endian_uint32(f, samples))
+               goto foo;
+       if(!write_big_endian_uint16(f, (FLAC__uint16)bps))
+               goto foo;
+       if(!write_sane_extended(f, sample_rate))
+               goto foo;
+       if(fwrite("SSND", 1, 4, f) < 4)
+               goto foo;
+       if(!write_big_endian_uint32(f, true_size + 8))
+               goto foo;
+       if(fwrite("\000\000\000\000\000\000\000\000", 1, 8, f) < 8)
+               goto foo;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               for(j = 0; j < channels; j++) {
+                       double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+                       FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+                       if(!write_big_endian(f, v, bytes_per_sample))
+                               goto foo;
+               }
+       }
+       for(i = true_size; i < padded_size; i++)
+               if(fputc(0, f) == EOF)
+                       goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict)
+{
+       const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps%8));
+       /*                                                                 ^^^^^^^
+        * (bps%8) allows 24 bps which is technically supposed to be WAVEFORMATEXTENSIBLE but we
+        * write 24bps as WAVEFORMATEX since it's unambiguous and matches how flac writes it
+        */
+       const unsigned bytes_per_sample = (bps+7)/8;
+       const unsigned true_size = channels * bytes_per_sample * samples;
+       const unsigned padded_size = (true_size + 1) & (~1u);
+       const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+       const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+       const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+       const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+       const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+       double theta1, theta2;
+       FILE *f;
+       unsigned i, j;
+
+       if(0 == (f = fopen(filename, "wb")))
+               return false;
+       if(fwrite("RIFF", 1, 4, f) < 4)
+               goto foo;
+       if(!write_little_endian_uint32(f, padded_size + (waveformatextensible?60:36)))
+               goto foo;
+       if(fwrite("WAVEfmt ", 1, 8, f) < 8)
+               goto foo;
+       if(!write_little_endian_uint32(f, waveformatextensible?40:16))
+               goto foo;
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1)))
+               goto foo;
+       if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
+               goto foo;
+       if(!write_little_endian_uint32(f, sample_rate))
+               goto foo;
+       if(!write_little_endian_uint32(f, sample_rate * channels * bytes_per_sample))
+               goto foo;
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * bytes_per_sample))) /* block align */
+               goto foo;
+       if(!write_little_endian_uint16(f, (FLAC__uint16)(bps+shift)))
+               goto foo;
+       if(waveformatextensible) {
+               if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */
+                       goto foo;
+               if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */
+                       goto foo;
+               if(!write_little_endian_uint32(f, 0)) /* channelMask */
+                       goto foo;
+               /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+               if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+                       goto foo;
+       }
+       if(fwrite("data", 1, 4, f) < 4)
+               goto foo;
+       if(!write_little_endian_uint32(f, true_size))
+               goto foo;
+
+       for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+               for(j = 0; j < channels; j++) {
+                       double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+                       FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+                       if(!write_little_endian(f, v, bytes_per_sample))
+                               goto foo;
+               }
+       }
+       for(i = true_size; i < padded_size; i++)
+               if(fputc(0, f) == EOF)
+                       goto foo;
+
+       fclose(f);
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+static FLAC__bool generate_wackywavs(void)
+{
+       FILE *f;
+       FLAC__byte wav[] = {
+               'R', 'I', 'F', 'F',  76,   0,   0,   0,
+               'W', 'A', 'V', 'E', 'f', 'a', 'c', 't',
+                 4,   0,   0,  0 , 'b', 'l', 'a', 'h',
+               'p', 'a', 'd', ' ',   4,   0,   0,   0,
+               'B', 'L', 'A', 'H', 'f', 'm', 't', ' ',
+                16,   0,   0,   0,   1,   0,   1,   0,
+               0x44,0xAC,  0,   0,   0,   0,   0,   0,
+                 2,   0,  16,   0, 'd', 'a', 't', 'a',
+                16,   0,   0,   0,   0,   0,   1,   0,
+                 4,   0,   9,   0,  16,   0,  25,   0,
+                36,   0,  49,   0, 'p', 'a', 'd', ' ',
+                 4,   0,   0,   0, 'b', 'l', 'a', 'h'
+       };
+
+       if(0 == (f = fopen("wacky1.wav", "wb")))
+               return false;
+       if(fwrite(wav, 1, 84, f) < 84)
+               goto foo;
+       fclose(f);
+
+       wav[4] += 12;
+       if(0 == (f = fopen("wacky2.wav", "wb")))
+               return false;
+       if(fwrite(wav, 1, 96, f) < 96)
+               goto foo;
+       fclose(f);
+
+       return true;
+foo:
+       fclose(f);
+       return false;
+}
+
+int main(int argc, char *argv[])
+{
+       FLAC__uint32 test = 1;
+       unsigned channels;
+
+       int pattern01[] = { 1, -1, 0 };
+       int pattern02[] = { 1, 1, -1, 0 };
+       int pattern03[] = { 1, -1, -1, 0 };
+       int pattern04[] = { 1, -1, 1, -1, 0 };
+       int pattern05[] = { 1, -1, -1, 1, 0 };
+       int pattern06[] = { 1, -1, 1, 1, -1, 0 };
+       int pattern07[] = { 1, -1, -1, 1, -1, 0 };
+
+       (void)argc;
+       (void)argv;
+       is_big_endian_host = (*((FLAC__byte*)(&test)))? false : true;
+
+#if !defined _MSC_VER && !defined __MINGW32__
+       {
+               struct timeval tv;
+
+               if(gettimeofday(&tv, 0) < 0) {
+                       fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+                       tv.tv_usec = 4321;
+               }
+               srandom(tv.tv_usec);
+       }
+#else
+       srand((unsigned)time(0));
+#endif
+
+       if(!generate_01()) return 1;
+       if(!generate_02()) return 1;
+       if(!generate_03()) return 1;
+       if(!generate_04()) return 1;
+
+       if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1;
+       if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1;
+       if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1;
+       if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1;
+       if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1;
+       if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1;
+       if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1;
+
+       if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1;
+       if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1;
+       if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1;
+       if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1;
+       if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1;
+       if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1;
+       if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1;
+
+       if(!generate_fsd24("fsd24-01.raw", pattern01, 100)) return 1;
+       if(!generate_fsd24("fsd24-02.raw", pattern02, 100)) return 1;
+       if(!generate_fsd24("fsd24-03.raw", pattern03, 100)) return 1;
+       if(!generate_fsd24("fsd24-04.raw", pattern04, 100)) return 1;
+       if(!generate_fsd24("fsd24-05.raw", pattern05, 100)) return 1;
+       if(!generate_fsd24("fsd24-06.raw", pattern06, 100)) return 1;
+       if(!generate_fsd24("fsd24-07.raw", pattern07, 100)) return 1;
+
+       if(!generate_wbps16("wbps16-01.raw", 1000)) return 1;
+
+       if(!generate_sine8_1("sine8-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+       if(!generate_sine8_1("sine8-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+       if(!generate_sine8_1("sine8-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+       if(!generate_sine8_1("sine8-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+       if(!generate_sine8_1("sine8-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+       if(!generate_sine8_2("sine8-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+       if(!generate_sine8_2("sine8-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+       if(!generate_sine8_2("sine8-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+       if(!generate_sine8_2("sine8-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+       if(!generate_sine8_2("sine8-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+       if(!generate_sine8_2("sine8-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+       if(!generate_sine8_2("sine8-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+       if(!generate_sine8_2("sine8-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+       if(!generate_sine8_2("sine8-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+       if(!generate_sine8_2("sine8-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+       if(!generate_sine16_1("sine16-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+       if(!generate_sine16_1("sine16-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+       if(!generate_sine16_1("sine16-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+       if(!generate_sine16_1("sine16-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+       if(!generate_sine16_1("sine16-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+       if(!generate_sine16_2("sine16-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+       if(!generate_sine16_2("sine16-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+       if(!generate_sine16_2("sine16-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+       if(!generate_sine16_2("sine16-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+       if(!generate_sine16_2("sine16-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+       if(!generate_sine16_2("sine16-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+       if(!generate_sine16_2("sine16-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+       if(!generate_sine16_2("sine16-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+       if(!generate_sine16_2("sine16-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+       if(!generate_sine16_2("sine16-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+       if(!generate_sine24_1("sine24-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+       if(!generate_sine24_1("sine24-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+       if(!generate_sine24_1("sine24-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+       if(!generate_sine24_1("sine24-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+       if(!generate_sine24_1("sine24-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+       if(!generate_sine24_2("sine24-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+       if(!generate_sine24_2("sine24-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+       if(!generate_sine24_2("sine24-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+       if(!generate_sine24_2("sine24-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+       if(!generate_sine24_2("sine24-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+       if(!generate_sine24_2("sine24-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+       if(!generate_sine24_2("sine24-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+       if(!generate_sine24_2("sine24-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+       if(!generate_sine24_2("sine24-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+       if(!generate_sine24_2("sine24-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+       /* WATCHOUT: the size of noise.raw is hardcoded into test/test_flac.sh */
+       if(!generate_noise("noise.raw", 65536 * 8 * 3)) return 1;
+       if(!generate_noise("noise8m32.raw", 32)) return 1;
+       if(!generate_wackywavs()) return 1;
+       for(channels = 1; channels <= 8; channels++) {
+               unsigned bits_per_sample;
+               for(bits_per_sample = 4; bits_per_sample <= 24; bits_per_sample++) {
+                       static const unsigned nsamples[] = { 1, 111, 4777 } ;
+                       unsigned samples;
+                       for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) {
+                               char fn[64];
+
+                               sprintf(fn, "rt-%u-%u-%u.aiff", channels, bits_per_sample, nsamples[samples]);
+                               if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples]))
+                                       return 1;
+
+                               sprintf(fn, "rt-%u-%u-%u.wav", channels, bits_per_sample, nsamples[samples]);
+                               if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true))
+                                       return 1;
+
+                               if(bits_per_sample % 8 == 0) {
+                                       sprintf(fn, "rt-%u-%u-%u.raw", channels, bits_per_sample, nsamples[samples]);
+                                       if(!generate_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+                                               return 1;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/src/test_streams/test_streams.dsp b/src/test_streams/test_streams.dsp
new file mode 100644 (file)
index 0000000..86e0bc4
--- /dev/null
@@ -0,0 +1,96 @@
+# Microsoft Developer Studio Project File - Name="test_streams" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=test_streams - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_streams.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "test_streams.mak" CFG="test_streams - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "test_streams - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "test_streams - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "test_streams - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\..\obj\release\bin"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "test_streams - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\..\obj\debug\bin"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "test_streams - Win32 Release"\r
+# Name "test_streams - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "c"\r
+# Begin Source File\r
+\r
+SOURCE=.\main.c\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/src/test_streams/test_streams.vcproj b/src/test_streams/test_streams.vcproj
new file mode 100644 (file)
index 0000000..3868fe7
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="test_streams"\r
+       ProjectGUID="{4cefbc91-c215-11db-8314-0800200c9a66}"\r
+       RootNamespace="test_streams"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="..\..\obj\debug\bin"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__NO_DLL;DEBUG"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="..\..\obj\release\bin"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               EnableIntrinsicFunctions="true"\r
+                               FavorSizeOrSpeed="1"\r
+                               OmitFramePointers="true"\r
+                               WholeProgramOptimization="true"\r
+                               AdditionalIncludeDirectories=".;..\..\include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__NO_DLL"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                               DisableSpecificWarnings="4267;4996"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               IgnoreDefaultLibraryNames="uuid.lib"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/strip_non_asm_libtool_args.sh b/strip_non_asm_libtool_args.sh
new file mode 100755 (executable)
index 0000000..d5a61f1
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# libtool assumes that the compiler can handle the -fPIC flag.
+# This isn't always true (for example, nasm can't handle it).
+# Also, on some versions of OS X it tries to pass -fno-common
+# to 'as' which causes problems.
+command=""
+while [ $1 ]; do
+       if [ "$1" != "-fPIC" ]; then
+               if [ "$1" != "-DPIC" ]; then
+                       if [ "$1" != "-fno-common" ]; then
+                               command="$command $1"
+                       fi
+               fi
+       fi
+       shift
+done
+echo $command
+exec $command
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644 (file)
index 0000000..bf6e4f4
--- /dev/null
@@ -0,0 +1,51 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+if FLaC__WITH_CPPLIBS
+CPPLIBS_TESTS = test_libFLAC++.sh
+endif
+
+TESTS_ENVIRONMENT = FLAC__TEST_LEVEL=@FLAC__TEST_LEVEL@ FLAC__TEST_WITH_VALRGIND=@FLAC__TEST_WITH_VALGRIND@
+
+SUBDIRS = cuesheets flac-to-flac-metadata-test-files metaflac-test-files pictures
+
+TESTS = \
+       ./test_libFLAC.sh \
+       $(CPPLIBS_TESTS) \
+       ./test_grabbag.sh \
+       ./test_flac.sh \
+       ./test_metaflac.sh \
+       ./test_seeking.sh \
+       ./test_streams.sh
+
+EXTRA_DIST = \
+       Makefile.lite \
+       cuesheet.ok \
+       metaflac.flac.in \
+       metaflac.flac.ok \
+       picture.ok \
+       test_libFLAC.sh \
+       $(CPPLIBS_TESTS) \
+       test_flac.sh \
+       test_metaflac.sh \
+       test_grabbag.sh \
+       test_seeking.sh \
+       test_streams.sh \
+       test_bins.sh
+
+clean-local:
+       -rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.diff *.log *.cue core
diff --git a/test/Makefile.lite b/test/Makefile.lite
new file mode 100644 (file)
index 0000000..2a05ab7
--- /dev/null
@@ -0,0 +1,55 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+#
+# GNU makefile
+#
+
+topdir = ..
+
+DEFAULT_CONFIG = release
+
+CONFIG = $(DEFAULT_CONFIG)
+
+all: clean
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_libFLAC.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_libFLAC++.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_grabbag.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_flac.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_metaflac.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_seeking.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_streams.sh $(CONFIG)
+       $(FLAC__TEST_LEVEL) $(FLAC__TEST_WITH_VALGRIND) ./test_bins.sh $(CONFIG)
+
+debug   : FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=2
+valgrind: FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=1
+release : FLAC__TEST_LEVEL=FLAC__TEST_LEVEL=2
+
+debug   : FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=no
+valgrind: FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=yes
+release : FLAC__TEST_WITH_VALGRIND=FLAC__TEST_WITH_VALGRIND=no
+
+debug   : CONFIG = debug
+valgrind: CONFIG = debug
+release : CONFIG = release
+
+debug   : all
+valgrind: all
+release : all
+
+clean:
+       rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.diff *.log *.cue core flac-to-flac-metadata-test-files/out.* metaflac-test-files/out.*
diff --git a/test/cuesheet.ok b/test/cuesheet.ok
new file mode 100644 (file)
index 0000000..c57f833
--- /dev/null
@@ -0,0 +1,93 @@
+NEGATIVE cuesheets/bad.000.CATALOG_multiple.cue
+pass1: parse error, line 2: "found multiple CATALOG commands"
+NEGATIVE cuesheets/bad.001.CATALOG_missing_number.cue
+pass1: parse error, line 1: "CATALOG is missing catalog number"
+NEGATIVE cuesheets/bad.002.CATALOG_number_too_long.cue
+pass1: parse error, line 1: "CATALOG number is too long"
+NEGATIVE cuesheets/bad.003.CATALOG_not_13_digits.cue
+pass1: parse error, line 1: "CD-DA CATALOG number must be 13 decimal digits"
+NEGATIVE cuesheets/bad.030.FLAGS_multiple.cue
+pass1: parse error, line 4: "found multiple FLAGS commands"
+NEGATIVE cuesheets/bad.031.FLAGS_wrong_place_1.cue
+pass1: parse error, line 1: "FLAGS command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.032.FLAGS_wrong_place_2.cue
+pass1: parse error, line 4: "FLAGS command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.060.INDEX_wrong_place.cue
+pass1: parse error, line 2: "found INDEX before any TRACK"
+NEGATIVE cuesheets/bad.061.INDEX_missing_number.cue
+pass1: parse error, line 4: "INDEX is missing index number"
+NEGATIVE cuesheets/bad.062.INDEX_invalid_number_1.cue
+pass1: parse error, line 4: "INDEX has invalid index number"
+NEGATIVE cuesheets/bad.063.first_INDEX_not_0_or_1.cue
+pass1: parse error, line 4: "first INDEX number of a TRACK must be 0 or 1"
+NEGATIVE cuesheets/bad.064.INDEX_num_non_sequential.cue
+pass1: parse error, line 5: "INDEX numbers must be sequential"
+NEGATIVE cuesheets/bad.065.INDEX_num_out_of_range.cue
+pass1: parse error, line 104: "CD-DA INDEX number must be between 0 and 99, inclusive"
+NEGATIVE cuesheets/bad.066.INDEX_missing_offset.cue
+pass1: parse error, line 4: "INDEX is missing an offset after the index number"
+NEGATIVE cuesheets/bad.067.INDEX_illegal_offset.cue
+pass1: parse error, line 4: "illegal INDEX offset (not of the form MM:SS:FF)"
+NEGATIVE cuesheets/bad.068.INDEX_cdda_illegal_offset.cue
+pass1: parse error, line 4: "illegal INDEX offset (not of the form MM:SS:FF)"
+NEGATIVE cuesheets/bad.069.nonzero_first_INDEX.cue
+pass1: parse error, line 4: "first INDEX of first TRACK must have an offset of 00:00:00"
+NEGATIVE cuesheets/bad.070.INDEX_offset_not_ascending_1.cue
+pass1: parse error, line 5: "CD-DA INDEX offsets must increase in time"
+NEGATIVE cuesheets/bad.071.INDEX_offset_not_ascending_2.cue
+pass1: parse error, line 6: "CD-DA INDEX offsets must increase in time"
+NEGATIVE cuesheets/bad.110.ISRC_multiple.cue
+pass1: parse error, line 4: "found multiple ISRC commands"
+NEGATIVE cuesheets/bad.111.ISRC_wrong_place_1.cue
+pass1: parse error, line 2: "ISRC command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.112.ISRC_wrong_place_2.cue
+pass1: parse error, line 4: "ISRC command must come after TRACK but before INDEX"
+NEGATIVE cuesheets/bad.113.ISRC_missing_number.cue
+pass1: parse error, line 3: "ISRC is missing ISRC number"
+NEGATIVE cuesheets/bad.114.ISRC_invalid_number.cue
+pass1: parse error, line 3: "invalid ISRC number"
+NEGATIVE cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue
+pass1: parse error, line 2: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue
+pass1: parse error, line 3: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue
+pass1: parse error, line 3: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue
+pass1: parse error, line 4: "previous TRACK must specify at least one INDEX 01"
+NEGATIVE cuesheets/bad.134.TRACK_missing_number.cue
+pass1: parse error, line 2: "TRACK is missing track number"
+NEGATIVE cuesheets/bad.135.TRACK_invalid_number_1.cue
+pass1: parse error, line 2: "TRACK has invalid track number"
+NEGATIVE cuesheets/bad.136.TRACK_invalid_number_2.cue
+pass1: parse error, line 2: "TRACK number must be greater than 0"
+NEGATIVE cuesheets/bad.137.TRACK_cdda_out_of_range.cue
+pass1: parse error, line 2: "CD-DA TRACK number must be between 1 and 99, inclusive"
+NEGATIVE cuesheets/bad.138.TRACK_num_non_sequential.cue
+pass1: parse error, line 6: "CD-DA TRACK numbers must be sequential"
+NEGATIVE cuesheets/bad.139.TRACK_missing_type.cue
+pass1: parse error, line 2: "TRACK is missing a track type after the track number"
+NEGATIVE cuesheets/bad.140.no_TRACKs.cue
+pass1: parse error, line 1: "there must be at least one TRACK command"
+NEGATIVE cuesheets/bad.200.FLAC_leadin_missing_offset.cue
+pass1: parse error, line 1: "FLAC__lead-in is missing offset"
+NEGATIVE cuesheets/bad.201.FLAC_leadin_illegal_offset.cue
+pass1: parse error, line 1: "illegal FLAC__lead-in offset"
+NEGATIVE cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue
+pass1: parse error, line 1: "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples"
+NEGATIVE cuesheets/bad.230.FLAC_leadout_multiple.cue
+pass1: parse error, line 3: "multiple FLAC__lead-out commands"
+NEGATIVE cuesheets/bad.231.FLAC_leadout_missing_track.cue
+pass1: parse error, line 1: "FLAC__lead-out is missing track number"
+NEGATIVE cuesheets/bad.232.FLAC_leadout_illegal_track.cue
+pass1: parse error, line 1: "illegal FLAC__lead-out track number"
+NEGATIVE cuesheets/bad.233.FLAC_leadout_missing_offset.cue
+pass1: parse error, line 1: "FLAC__lead-out is missing offset"
+NEGATIVE cuesheets/bad.234.FLAC_leadout_illegal_offset.cue
+pass1: parse error, line 1: "illegal FLAC__lead-out offset"
+NEGATIVE cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue
+pass1: parse error, line 1: "FLAC__lead-out offset does not match end-of-stream offset"
+POSITIVE cuesheets/good.000.cue
+POSITIVE cuesheets/good.001.cue
+POSITIVE cuesheets/good.002.dos_format.cue
+POSITIVE cuesheets/good.003.missing_final_newline.cue
+POSITIVE cuesheets/good.004.dos_format.missing_final_newline.cue
diff --git a/test/cuesheets/Makefile.am b/test/cuesheets/Makefile.am
new file mode 100644 (file)
index 0000000..476ae06
--- /dev/null
@@ -0,0 +1,67 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       bad.000.CATALOG_multiple.cue \
+       bad.001.CATALOG_missing_number.cue \
+       bad.002.CATALOG_number_too_long.cue \
+       bad.003.CATALOG_not_13_digits.cue \
+       bad.030.FLAGS_multiple.cue \
+       bad.031.FLAGS_wrong_place_1.cue \
+       bad.032.FLAGS_wrong_place_2.cue \
+       bad.060.INDEX_wrong_place.cue \
+       bad.061.INDEX_missing_number.cue \
+       bad.062.INDEX_invalid_number_1.cue \
+       bad.063.first_INDEX_not_0_or_1.cue \
+       bad.064.INDEX_num_non_sequential.cue \
+       bad.065.INDEX_num_out_of_range.cue \
+       bad.066.INDEX_missing_offset.cue \
+       bad.067.INDEX_illegal_offset.cue \
+       bad.068.INDEX_cdda_illegal_offset.cue \
+       bad.069.nonzero_first_INDEX.cue \
+       bad.070.INDEX_offset_not_ascending_1.cue \
+       bad.071.INDEX_offset_not_ascending_2.cue \
+       bad.110.ISRC_multiple.cue \
+       bad.111.ISRC_wrong_place_1.cue \
+       bad.112.ISRC_wrong_place_2.cue \
+       bad.113.ISRC_missing_number.cue \
+       bad.114.ISRC_invalid_number.cue \
+       bad.130.TRACK_missing_INDEX_01_1.cue \
+       bad.131.TRACK_missing_INDEX_01_2.cue \
+       bad.132.TRACK_missing_INDEX_01_3.cue \
+       bad.133.TRACK_missing_INDEX_01_4.cue \
+       bad.134.TRACK_missing_number.cue \
+       bad.135.TRACK_invalid_number_1.cue \
+       bad.136.TRACK_invalid_number_2.cue \
+       bad.137.TRACK_cdda_out_of_range.cue \
+       bad.138.TRACK_num_non_sequential.cue \
+       bad.139.TRACK_missing_type.cue \
+       bad.140.no_TRACKs.cue \
+       bad.200.FLAC_leadin_missing_offset.cue \
+       bad.201.FLAC_leadin_illegal_offset.cue \
+       bad.202.FLAC_leadin_cdda_illegal_offset.cue \
+       bad.230.FLAC_leadout_multiple.cue \
+       bad.231.FLAC_leadout_missing_track.cue \
+       bad.232.FLAC_leadout_illegal_track.cue \
+       bad.233.FLAC_leadout_missing_offset.cue \
+       bad.234.FLAC_leadout_illegal_offset.cue \
+       bad.235.FLAC_leadout_offset_not_211680000.cue \
+       good.000.cue \
+       good.001.cue \
+       good.002.dos_format.cue \
+       good.003.missing_final_newline.cue \
+       good.004.dos_format.missing_final_newline.cue
diff --git a/test/cuesheets/bad.000.CATALOG_multiple.cue b/test/cuesheets/bad.000.CATALOG_multiple.cue
new file mode 100644 (file)
index 0000000..ef2769b
--- /dev/null
@@ -0,0 +1,5 @@
+CATALOG 1234567890123
+CATALOG 0234567890123
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.001.CATALOG_missing_number.cue b/test/cuesheets/bad.001.CATALOG_missing_number.cue
new file mode 100644 (file)
index 0000000..ce2334f
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG 
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.002.CATALOG_number_too_long.cue b/test/cuesheets/bad.002.CATALOG_number_too_long.cue
new file mode 100644 (file)
index 0000000..8585a0a
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.003.CATALOG_not_13_digits.cue b/test/cuesheets/bad.003.CATALOG_not_13_digits.cue
new file mode 100644 (file)
index 0000000..c75d4c0
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG 123456789012z
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.030.FLAGS_multiple.cue b/test/cuesheets/bad.030.FLAGS_multiple.cue
new file mode 100644 (file)
index 0000000..ee82b13
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    FLAGS 4CH
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.031.FLAGS_wrong_place_1.cue b/test/cuesheets/bad.031.FLAGS_wrong_place_1.cue
new file mode 100644 (file)
index 0000000..3b7f018
--- /dev/null
@@ -0,0 +1,4 @@
+FLAGS PRE
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.032.FLAGS_wrong_place_2.cue b/test/cuesheets/bad.032.FLAGS_wrong_place_2.cue
new file mode 100644 (file)
index 0000000..926cc91
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    FLAGS PRE
diff --git a/test/cuesheets/bad.060.INDEX_wrong_place.cue b/test/cuesheets/bad.060.INDEX_wrong_place.cue
new file mode 100644 (file)
index 0000000..fb175f2
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+INDEX 00 00:00:00
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.061.INDEX_missing_number.cue b/test/cuesheets/bad.061.INDEX_missing_number.cue
new file mode 100644 (file)
index 0000000..bf72604
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 
diff --git a/test/cuesheets/bad.062.INDEX_invalid_number_1.cue b/test/cuesheets/bad.062.INDEX_invalid_number_1.cue
new file mode 100644 (file)
index 0000000..fcb4dd3
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX thhpt!
diff --git a/test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue b/test/cuesheets/bad.063.first_INDEX_not_0_or_1.cue
new file mode 100644 (file)
index 0000000..a136f3f
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 02 00:00:00
diff --git a/test/cuesheets/bad.064.INDEX_num_non_sequential.cue b/test/cuesheets/bad.064.INDEX_num_non_sequential.cue
new file mode 100644 (file)
index 0000000..9df3b47
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
+    INDEX 00 00:00:00
diff --git a/test/cuesheets/bad.065.INDEX_num_out_of_range.cue b/test/cuesheets/bad.065.INDEX_num_out_of_range.cue
new file mode 100644 (file)
index 0000000..a72d7e0
--- /dev/null
@@ -0,0 +1,104 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 00 00:00:00
+    INDEX 01 02:10:15
+    INDEX 02 02:20:15
+    INDEX 03 02:30:15
+    INDEX 04 03:30:15
+    INDEX 05 03:31:15
+    INDEX 06 03:32:06
+    INDEX 07 03:32:07
+    INDEX 08 03:32:08
+    INDEX 09 03:32:09
+    INDEX 10 03:32:10
+    INDEX 11 03:32:11
+    INDEX 12 03:32:12
+    INDEX 13 03:32:13
+    INDEX 14 03:32:14
+    INDEX 15 03:32:15
+    INDEX 16 03:32:16
+    INDEX 17 03:32:17
+    INDEX 18 03:32:18
+    INDEX 19 03:32:19
+    INDEX 20 03:32:20
+    INDEX 21 03:32:21
+    INDEX 22 03:32:22
+    INDEX 23 03:32:23
+    INDEX 24 03:32:24
+    INDEX 25 03:32:25
+    INDEX 26 03:32:26
+    INDEX 27 03:32:27
+    INDEX 28 03:32:28
+    INDEX 29 03:32:29
+    INDEX 30 03:32:30
+    INDEX 31 03:32:31
+    INDEX 32 03:32:32
+    INDEX 33 03:32:33
+    INDEX 34 03:32:34
+    INDEX 35 03:32:35
+    INDEX 36 03:32:36
+    INDEX 37 03:32:37
+    INDEX 38 03:32:38
+    INDEX 39 03:32:39
+    INDEX 40 03:32:40
+    INDEX 41 03:32:41
+    INDEX 42 03:32:42
+    INDEX 43 03:32:43
+    INDEX 44 03:32:44
+    INDEX 45 03:32:45
+    INDEX 46 03:32:46
+    INDEX 47 03:32:47
+    INDEX 48 03:32:48
+    INDEX 49 03:32:49
+    INDEX 50 03:32:50
+    INDEX 51 03:32:51
+    INDEX 52 03:32:52
+    INDEX 53 03:32:53
+    INDEX 54 03:32:54
+    INDEX 55 03:32:55
+    INDEX 56 03:32:56
+    INDEX 57 03:32:57
+    INDEX 58 03:32:58
+    INDEX 59 03:32:59
+    INDEX 60 03:32:60
+    INDEX 61 03:32:61
+    INDEX 62 03:32:62
+    INDEX 63 03:32:63
+    INDEX 64 03:32:64
+    INDEX 65 03:32:65
+    INDEX 66 03:32:66
+    INDEX 67 03:32:67
+    INDEX 68 03:32:68
+    INDEX 69 03:32:69
+    INDEX 70 03:40:50
+    INDEX 71 03:40:51
+    INDEX 72 03:40:52
+    INDEX 73 03:40:53
+    INDEX 74 03:40:54
+    INDEX 75 03:40:55
+    INDEX 76 03:40:56
+    INDEX 77 03:40:57
+    INDEX 78 03:40:58
+    INDEX 79 03:40:59
+    INDEX 80 03:41:50
+    INDEX 81 03:41:51
+    INDEX 82 03:41:52
+    INDEX 83 03:41:53
+    INDEX 84 03:41:54
+    INDEX 85 03:41:55
+    INDEX 86 03:41:56
+    INDEX 87 03:41:57
+    INDEX 88 03:41:58
+    INDEX 89 03:41:59
+    INDEX 90 03:42:50
+    INDEX 91 03:42:51
+    INDEX 92 03:42:52
+    INDEX 93 03:42:53
+    INDEX 94 03:42:54
+    INDEX 95 03:42:55
+    INDEX 96 03:42:56
+    INDEX 97 03:42:57
+    INDEX 98 03:42:58
+    INDEX 99 03:42:59
+    INDEX 100 04:00:00
diff --git a/test/cuesheets/bad.066.INDEX_missing_offset.cue b/test/cuesheets/bad.066.INDEX_missing_offset.cue
new file mode 100644 (file)
index 0000000..1e78bc6
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 
diff --git a/test/cuesheets/bad.067.INDEX_illegal_offset.cue b/test/cuesheets/bad.067.INDEX_illegal_offset.cue
new file mode 100644 (file)
index 0000000..8742029
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00.00
diff --git a/test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue b/test/cuesheets/bad.068.INDEX_cdda_illegal_offset.cue
new file mode 100644 (file)
index 0000000..6e00fed
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 588
diff --git a/test/cuesheets/bad.069.nonzero_first_INDEX.cue b/test/cuesheets/bad.069.nonzero_first_INDEX.cue
new file mode 100644 (file)
index 0000000..7464949
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue b/test/cuesheets/bad.070.INDEX_offset_not_ascending_1.cue
new file mode 100644 (file)
index 0000000..a4fe063
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+       INDEX 02 00:02:00
+       INDEX 03 00:01:74
diff --git a/test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue b/test/cuesheets/bad.071.INDEX_offset_not_ascending_2.cue
new file mode 100644 (file)
index 0000000..8983a03
--- /dev/null
@@ -0,0 +1,6 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    INDEX 02 00:02:00
+  TRACK 02 AUDIO
+    INDEX 01 00:01:74
diff --git a/test/cuesheets/bad.110.ISRC_multiple.cue b/test/cuesheets/bad.110.ISRC_multiple.cue
new file mode 100644 (file)
index 0000000..907c1b8
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC ABCDE1234567
+    ISRC ABCD01234567
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.111.ISRC_wrong_place_1.cue b/test/cuesheets/bad.111.ISRC_wrong_place_1.cue
new file mode 100644 (file)
index 0000000..86fbe90
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+ISRC ABCD01234567
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.112.ISRC_wrong_place_2.cue b/test/cuesheets/bad.112.ISRC_wrong_place_2.cue
new file mode 100644 (file)
index 0000000..e0b4e77
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+    ISRC ABCD01234567
diff --git a/test/cuesheets/bad.113.ISRC_missing_number.cue b/test/cuesheets/bad.113.ISRC_missing_number.cue
new file mode 100644 (file)
index 0000000..742e054
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.114.ISRC_invalid_number.cue b/test/cuesheets/bad.114.ISRC_invalid_number.cue
new file mode 100644 (file)
index 0000000..362130a
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    ISRC ABCD0123456Z
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue b/test/cuesheets/bad.130.TRACK_missing_INDEX_01_1.cue
new file mode 100644 (file)
index 0000000..0697074
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
diff --git a/test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue b/test/cuesheets/bad.131.TRACK_missing_INDEX_01_2.cue
new file mode 100644 (file)
index 0000000..554cf12
--- /dev/null
@@ -0,0 +1,3 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 00 00:00:00
diff --git a/test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue b/test/cuesheets/bad.132.TRACK_missing_INDEX_01_3.cue
new file mode 100644 (file)
index 0000000..5618db8
--- /dev/null
@@ -0,0 +1,4 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+  TRACK 02 AUDIO
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue b/test/cuesheets/bad.133.TRACK_missing_INDEX_01_4.cue
new file mode 100644 (file)
index 0000000..f74a9e4
--- /dev/null
@@ -0,0 +1,5 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 00 00:00:00
+  TRACK 02 AUDIO
+    INDEX 01 00:02:00
diff --git a/test/cuesheets/bad.134.TRACK_missing_number.cue b/test/cuesheets/bad.134.TRACK_missing_number.cue
new file mode 100644 (file)
index 0000000..f95180b
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 
diff --git a/test/cuesheets/bad.135.TRACK_invalid_number_1.cue b/test/cuesheets/bad.135.TRACK_invalid_number_1.cue
new file mode 100644 (file)
index 0000000..9c3c9ea
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK thhpt! AUDIO
diff --git a/test/cuesheets/bad.136.TRACK_invalid_number_2.cue b/test/cuesheets/bad.136.TRACK_invalid_number_2.cue
new file mode 100644 (file)
index 0000000..69caafa
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 0 AUDIO
diff --git a/test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue b/test/cuesheets/bad.137.TRACK_cdda_out_of_range.cue
new file mode 100644 (file)
index 0000000..8696f52
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 100 AUDIO
diff --git a/test/cuesheets/bad.138.TRACK_num_non_sequential.cue b/test/cuesheets/bad.138.TRACK_num_non_sequential.cue
new file mode 100644 (file)
index 0000000..37870c3
--- /dev/null
@@ -0,0 +1,6 @@
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 0:0:0
+  TRACK 02 AUDIO
+    INDEX 01 2:0:0
+  TRACK 01 AUDIO
diff --git a/test/cuesheets/bad.139.TRACK_missing_type.cue b/test/cuesheets/bad.139.TRACK_missing_type.cue
new file mode 100644 (file)
index 0000000..01fca6a
--- /dev/null
@@ -0,0 +1,2 @@
+FILE "z.wav" WAVE
+  TRACK 01
diff --git a/test/cuesheets/bad.140.no_TRACKs.cue b/test/cuesheets/bad.140.no_TRACKs.cue
new file mode 100644 (file)
index 0000000..73cb8cf
--- /dev/null
@@ -0,0 +1 @@
+FILE "z.wav" WAVE
diff --git a/test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue b/test/cuesheets/bad.200.FLAC_leadin_missing_offset.cue
new file mode 100644 (file)
index 0000000..7441aa5
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-in
diff --git a/test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue b/test/cuesheets/bad.201.FLAC_leadin_illegal_offset.cue
new file mode 100644 (file)
index 0000000..acf6940
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-in thhpt!
diff --git a/test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue b/test/cuesheets/bad.202.FLAC_leadin_cdda_illegal_offset.cue
new file mode 100644 (file)
index 0000000..6f2d0f7
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-in 123
diff --git a/test/cuesheets/bad.230.FLAC_leadout_multiple.cue b/test/cuesheets/bad.230.FLAC_leadout_multiple.cue
new file mode 100644 (file)
index 0000000..656fe9d
--- /dev/null
@@ -0,0 +1,3 @@
+REM FLAC__lead-in 88200
+REM FLAC__lead-out 170 211680000
+REM FLAC__lead-out 170 211680588
diff --git a/test/cuesheets/bad.231.FLAC_leadout_missing_track.cue b/test/cuesheets/bad.231.FLAC_leadout_missing_track.cue
new file mode 100644 (file)
index 0000000..a723b7a
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-out 
diff --git a/test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue b/test/cuesheets/bad.232.FLAC_leadout_illegal_track.cue
new file mode 100644 (file)
index 0000000..6001826
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-out thhpt!
diff --git a/test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue b/test/cuesheets/bad.233.FLAC_leadout_missing_offset.cue
new file mode 100644 (file)
index 0000000..ef5f1dc
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-out 170
diff --git a/test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue b/test/cuesheets/bad.234.FLAC_leadout_illegal_offset.cue
new file mode 100644 (file)
index 0000000..01c69f4
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-out 170 thhpt!
diff --git a/test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue b/test/cuesheets/bad.235.FLAC_leadout_offset_not_211680000.cue
new file mode 100644 (file)
index 0000000..8add1d6
--- /dev/null
@@ -0,0 +1 @@
+REM FLAC__lead-out 170 211680588
diff --git a/test/cuesheets/good.000.cue b/test/cuesheets/good.000.cue
new file mode 100644 (file)
index 0000000..bdfbccf
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
diff --git a/test/cuesheets/good.001.cue b/test/cuesheets/good.001.cue
new file mode 100644 (file)
index 0000000..f9887cf
--- /dev/null
@@ -0,0 +1,184 @@
+REM FLAC__lead-in 88200
+REM FLAC__lead-out 170 211680000
+CATALOG 1234567890123
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    FLAGS PRE
+    INDEX 01 00:00:00
+  TRACK 02 AUDIO
+    FLAGS PRE
+    ISRC ABCDE7654321
+    INDEX 00 02:09:12
+    INDEX 01 02:10:15
+    INDEX 02 02:20:15
+    INDEX 03 02:30:15
+    INDEX 04 03:30:15
+    INDEX 05 03:31:15
+    INDEX 06 03:32:06
+    INDEX 07 03:32:07
+    INDEX 08 03:32:08
+    INDEX 09 03:32:09
+    INDEX 10 03:32:10
+    INDEX 11 03:32:11
+    INDEX 12 03:32:12
+    INDEX 13 03:32:13
+    INDEX 14 03:32:14
+    INDEX 15 03:32:15
+    INDEX 16 03:32:16
+    INDEX 17 03:32:17
+    INDEX 18 03:32:18
+    INDEX 19 03:32:19
+    INDEX 20 03:32:20
+    INDEX 21 03:32:21
+    INDEX 22 03:32:22
+    INDEX 23 03:32:23
+    INDEX 24 03:32:24
+    INDEX 25 03:32:25
+    INDEX 26 03:32:26
+    INDEX 27 03:32:27
+    INDEX 28 03:32:28
+    INDEX 29 03:32:29
+    INDEX 30 03:32:30
+    INDEX 31 03:32:31
+    INDEX 32 03:32:32
+    INDEX 33 03:32:33
+    INDEX 34 03:32:34
+    INDEX 35 03:32:35
+    INDEX 36 03:32:36
+    INDEX 37 03:32:37
+    INDEX 38 03:32:38
+    INDEX 39 03:32:39
+    INDEX 40 03:32:40
+    INDEX 41 03:32:41
+    INDEX 42 03:32:42
+    INDEX 43 03:32:43
+    INDEX 44 03:32:44
+    INDEX 45 03:32:45
+    INDEX 46 03:32:46
+    INDEX 47 03:32:47
+    INDEX 48 03:32:48
+    INDEX 49 03:32:49
+    INDEX 50 03:32:50
+    INDEX 51 03:32:51
+    INDEX 52 03:32:52
+    INDEX 53 03:32:53
+    INDEX 54 03:32:54
+    INDEX 55 03:32:55
+    INDEX 56 03:32:56
+    INDEX 57 03:32:57
+    INDEX 58 03:32:58
+    INDEX 59 03:32:59
+    INDEX 60 03:32:60
+    INDEX 61 03:32:61
+    INDEX 62 03:32:62
+    INDEX 63 03:32:63
+    INDEX 64 03:32:64
+    INDEX 65 03:32:65
+    INDEX 66 03:32:66
+    INDEX 67 03:32:67
+    INDEX 68 03:32:68
+    INDEX 69 03:32:69
+    INDEX 70 03:40:50
+    INDEX 71 03:40:51
+    INDEX 72 03:40:52
+    INDEX 73 03:40:53
+    INDEX 74 03:40:54
+    INDEX 75 03:40:55
+    INDEX 76 03:40:56
+    INDEX 77 03:40:57
+    INDEX 78 03:40:58
+    INDEX 79 03:40:59
+    INDEX 80 03:41:50
+    INDEX 81 03:41:51
+    INDEX 82 03:41:52
+    INDEX 83 03:41:53
+    INDEX 84 03:41:54
+    INDEX 85 03:41:55
+    INDEX 86 03:41:56
+    INDEX 87 03:41:57
+    INDEX 88 03:41:58
+    INDEX 89 03:41:59
+    INDEX 90 03:42:50
+    INDEX 91 03:42:51
+    INDEX 92 03:42:52
+    INDEX 93 03:42:53
+    INDEX 94 03:42:54
+    INDEX 95 03:42:55
+    INDEX 96 03:42:56
+    INDEX 97 03:42:57
+    INDEX 98 03:42:58
+    INDEX 99 03:42:59
+  TRACK 03 AUDIO
+    ISRC AB-CD7-65-43210
+    INDEX 00 04:50:12
+    INDEX 01 04:51:72
+  TRACK 04 AUDIO
+    INDEX 00 06:36:10
+    INDEX 01 06:38:47
+  TRACK 05 AUDIO
+    INDEX 00 08:34:45
+    INDEX 01 08:36:15
+  TRACK 06 AUDIO
+    INDEX 00 13:20:22
+    INDEX 01 13:22:12
+  TRACK 07 AUDIO
+    INDEX 00 16:08:20
+    INDEX 01 16:11:17
+  TRACK 08 AUDIO
+    INDEX 01 17:48:37
+  TRACK 09 AUDIO
+    INDEX 00 19:38:17
+    INDEX 01 19:39:30
+  TRACK 10 AUDIO
+    INDEX 00 22:07:07
+    INDEX 01 22:08:20
+  TRACK 11 AUDIO
+    INDEX 01 24:16:45
+  TRACK 12 AUDIO
+    INDEX 01 26:13:67
+  TRACK 13 AUDIO
+    INDEX 01 28:03:27
+  TRACK 14 AUDIO
+    INDEX 00 30:22:42
+    INDEX 01 30:24:45
+  TRACK 15 AUDIO
+    INDEX 00 34:06:22
+    INDEX 01 34:07:62
+  TRACK 16 AUDIO
+    INDEX 00 35:54:30
+    INDEX 01 35:56:60
+  TRACK 17 AUDIO
+    INDEX 00 38:49:10
+    INDEX 01 38:51:22
+  TRACK 18 AUDIO
+    INDEX 00 41:14:15
+    INDEX 01 41:17:15
+  TRACK 19 AUDIO
+    INDEX 00 44:27:15
+    INDEX 01 44:28:45
+  TRACK 20 AUDIO
+    INDEX 00 48:07:17
+    INDEX 01 48:09:72
+  TRACK 21 AUDIO
+    INDEX 00 50:48:05
+    INDEX 01 50:49:27
+  TRACK 22 AUDIO
+    INDEX 00 53:29:72
+    INDEX 01 53:31:20
+  TRACK 23 AUDIO
+    INDEX 00 57:57:60
+    INDEX 01 58:00:40
+  TRACK 24 AUDIO
+    INDEX 00 61:52:65
+    INDEX 01 61:55:37
+  TRACK 25 AUDIO
+    INDEX 00 65:07:50
+    INDEX 01 65:10:52
+  TRACK 26 AUDIO
+    INDEX 00 68:30:05
+    INDEX 01 68:32:45
+  TRACK 27 AUDIO
+    INDEX 01 71:45:17
+  TRACK 28 AUDIO
+    INDEX 00 74:49:07
+    INDEX 01 74:51:47
diff --git a/test/cuesheets/good.002.dos_format.cue b/test/cuesheets/good.002.dos_format.cue
new file mode 100644 (file)
index 0000000..a60e03b
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"\r
+FILE "z.wav" WAVE\r
+  TRACK 01 AUDIO\r
+    INDEX 01 00:00:00\r
diff --git a/test/cuesheets/good.003.missing_final_newline.cue b/test/cuesheets/good.003.missing_final_newline.cue
new file mode 100644 (file)
index 0000000..a4c298f
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"
+FILE "z.wav" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
\ No newline at end of file
diff --git a/test/cuesheets/good.004.dos_format.missing_final_newline.cue b/test/cuesheets/good.004.dos_format.missing_final_newline.cue
new file mode 100644 (file)
index 0000000..1f6d0e5
--- /dev/null
@@ -0,0 +1,4 @@
+CATALOG "1234567890123"\r
+FILE "z.wav" WAVE\r
+  TRACK 01 AUDIO\r
+    INDEX 01 00:00:00
\ No newline at end of file
diff --git a/test/flac-to-flac-metadata-test-files/Makefile.am b/test/flac-to-flac-metadata-test-files/Makefile.am
new file mode 100644 (file)
index 0000000..511a2e2
--- /dev/null
@@ -0,0 +1,45 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       case00a-expect.meta \
+       case01a-expect.meta \
+       case01b-expect.meta \
+       case01c-expect.meta \
+       case01d-expect.meta \
+       case01e-expect.meta \
+       case02a-expect.meta \
+       case02b-expect.meta \
+       case02c-expect.meta \
+       case03a-expect.meta \
+       case03b-expect.meta \
+       case03c-expect.meta \
+       case04a-expect.meta \
+       case04b-expect.meta \
+       case04c-expect.meta \
+       case04d-expect.meta \
+       case04e-expect.meta \
+       input-SCPAP.flac \
+       input-SCVA.flac \
+       input-SCVAUP.flac \
+       input-SCVPAP.flac \
+       input-SVAUP.flac \
+       input-VA.flac \
+       input0.cue
+
+clean-local:
+       -rm -f out.*
diff --git a/test/flac-to-flac-metadata-test-files/case00a-expect.meta b/test/flac-to-flac-metadata-test-files/case00a-expect.meta
new file mode 100644 (file)
index 0000000..58bce54
--- /dev/null
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: 0
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 3201
diff --git a/test/flac-to-flac-metadata-test-files/case01a-expect.meta b/test/flac-to-flac-metadata-test-files/case01a-expect.meta
new file mode 100644 (file)
index 0000000..d82d277
--- /dev/null
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 3205
diff --git a/test/flac-to-flac-metadata-test-files/case01b-expect.meta b/test/flac-to-flac-metadata-test-files/case01b-expect.meta
new file mode 100644 (file)
index 0000000..2a6538d
--- /dev/null
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case01c-expect.meta b/test/flac-to-flac-metadata-test-files/case01c-expect.meta
new file mode 100644 (file)
index 0000000..0dd5f03
--- /dev/null
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 1234
diff --git a/test/flac-to-flac-metadata-test-files/case01d-expect.meta b/test/flac-to-flac-metadata-test-files/case01d-expect.meta
new file mode 100644 (file)
index 0000000..0dd5f03
--- /dev/null
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 1234
diff --git a/test/flac-to-flac-metadata-test-files/case01e-expect.meta b/test/flac-to-flac-metadata-test-files/case01e-expect.meta
new file mode 100644 (file)
index 0000000..33b7bdf
--- /dev/null
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 8192
diff --git a/test/flac-to-flac-metadata-test-files/case02a-expect.meta b/test/flac-to-flac-metadata-test-files/case02a-expect.meta
new file mode 100644 (file)
index 0000000..ef6cc46
--- /dev/null
@@ -0,0 +1,73 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 3205
diff --git a/test/flac-to-flac-metadata-test-files/case02b-expect.meta b/test/flac-to-flac-metadata-test-files/case02b-expect.meta
new file mode 100644 (file)
index 0000000..287d553
--- /dev/null
@@ -0,0 +1,74 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 52
+  comments: 1
+    comment[0]: artist=0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 3205
diff --git a/test/flac-to-flac-metadata-test-files/case02c-expect.meta b/test/flac-to-flac-metadata-test-files/case02c-expect.meta
new file mode 100644 (file)
index 0000000..14befce
--- /dev/null
@@ -0,0 +1,79 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 52
+  comments: 1
+    comment[0]: artist=0
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: 0
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 3201
diff --git a/test/flac-to-flac-metadata-test-files/case03a-expect.meta b/test/flac-to-flac-metadata-test-files/case03a-expect.meta
new file mode 100644 (file)
index 0000000..e04631b
--- /dev/null
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 9294969890929
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 588
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 2352
+          number: 2
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: 0
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 3201
diff --git a/test/flac-to-flac-metadata-test-files/case03b-expect.meta b/test/flac-to-flac-metadata-test-files/case03b-expect.meta
new file mode 100644 (file)
index 0000000..e04631b
--- /dev/null
@@ -0,0 +1,84 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 9294969890929
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 588
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 2352
+          number: 2
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 180
+  seek points: 10
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+    point 5: PLACEHOLDER
+    point 6: PLACEHOLDER
+    point 7: PLACEHOLDER
+    point 8: PLACEHOLDER
+    point 9: PLACEHOLDER
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #5
+  type: 126 (UNKNOWN)
+  is last: false
+  length: 0
+  data contents:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 3201
diff --git a/test/flac-to-flac-metadata-test-files/case03c-expect.meta b/test/flac-to-flac-metadata-test-files/case03c-expect.meta
new file mode 100644 (file)
index 0000000..378907d
--- /dev/null
@@ -0,0 +1,41 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5879
+  MD5 signature: 2ea0e6a767b66bf0668523fd77672ce1
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: false
+  length: 4
+  application ID: 66616b65
+  data contents:
+METADATA block #4
+  type: 126 (UNKNOWN)
+  is last: false
+  length: 0
+  data contents:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 3201
diff --git a/test/flac-to-flac-metadata-test-files/case04a-expect.meta b/test/flac-to-flac-metadata-test-files/case04a-expect.meta
new file mode 100644 (file)
index 0000000..ee9583d
--- /dev/null
@@ -0,0 +1,26 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #2
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04b-expect.meta b/test/flac-to-flac-metadata-test-files/case04b-expect.meta
new file mode 100644 (file)
index 0000000..036f428
--- /dev/null
@@ -0,0 +1,36 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 90
+  seek points: 5
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04c-expect.meta b/test/flac-to-flac-metadata-test-files/case04c-expect.meta
new file mode 100644 (file)
index 0000000..25f859e
--- /dev/null
@@ -0,0 +1,32 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04d-expect.meta b/test/flac-to-flac-metadata-test-files/case04d-expect.meta
new file mode 100644 (file)
index 0000000..4a7a964
--- /dev/null
@@ -0,0 +1,60 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #3
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/case04e-expect.meta b/test/flac-to-flac-metadata-test-files/case04e-expect.meta
new file mode 100644 (file)
index 0000000..065204e
--- /dev/null
@@ -0,0 +1,70 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 44100 Hz
+  channels: 2
+  bits-per-sample: 16
+  total samples: 5880
+  MD5 signature: 74ffd4737eb5488d512be4af58943362
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 90
+  seek points: 5
+    point 0: sample_number=0
+    point 1: sample_number=4096
+    point 2: PLACEHOLDER
+    point 3: PLACEHOLDER
+    point 4: PLACEHOLDER
+METADATA block #2
+  type: 5 (CUESHEET)
+  is last: false
+  length: 540
+  media catalog number: 1234567890123
+  lead-in: 88200
+  is CD: true
+  number of tracks: 3
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 2
+        index[0]
+          offset: 0
+          number: 1
+        index[1]
+          offset: 588
+          number: 2
+    track[1]
+      offset: 2940
+      number: 2
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[2]
+      offset: 5880
+      number: 170 (LEAD-OUT)
+METADATA block #3
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 203
+  comments: 6
+    comment[0]: REPLAYGAIN_TRACK_PEAK=0.99996948
+    comment[1]: REPLAYGAIN_TRACK_GAIN=-7.89 dB
+    comment[2]: REPLAYGAIN_ALBUM_PEAK=0.99996948
+    comment[3]: REPLAYGAIN_ALBUM_GAIN=-7.89 dB
+    comment[4]: artist=1
+    comment[5]: title=2
+METADATA block #4
+  type: 2 (APPLICATION)
+  is last: true
+  length: 4
+  application ID: 66616b65
+  data contents:
diff --git a/test/flac-to-flac-metadata-test-files/input-SCPAP.flac b/test/flac-to-flac-metadata-test-files/input-SCPAP.flac
new file mode 100644 (file)
index 0000000..6fde318
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-SCPAP.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVA.flac b/test/flac-to-flac-metadata-test-files/input-SCVA.flac
new file mode 100644 (file)
index 0000000..4bb6926
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-SCVA.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac b/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac
new file mode 100644 (file)
index 0000000..e4ecc95
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-SCVAUP.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac b/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac
new file mode 100644 (file)
index 0000000..7474928
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-SCVPAP.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input-SVAUP.flac b/test/flac-to-flac-metadata-test-files/input-SVAUP.flac
new file mode 100644 (file)
index 0000000..e3fa5c1
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-SVAUP.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input-VA.flac b/test/flac-to-flac-metadata-test-files/input-VA.flac
new file mode 100644 (file)
index 0000000..4fac878
Binary files /dev/null and b/test/flac-to-flac-metadata-test-files/input-VA.flac differ
diff --git a/test/flac-to-flac-metadata-test-files/input0.cue b/test/flac-to-flac-metadata-test-files/input0.cue
new file mode 100644 (file)
index 0000000..2894bd0
--- /dev/null
@@ -0,0 +1,7 @@
+CATALOG 9294969890929
+FILE "blah" FLAC
+  TRACK 01 AUDIO
+    INDEX 01 00:00:00
+  TRACK 02 AUDIO
+    INDEX 01 00:00:01
+    INDEX 02 00:00:05
diff --git a/test/metaflac-test-files/Makefile.am b/test/metaflac-test-files/Makefile.am
new file mode 100644 (file)
index 0000000..03dda7f
--- /dev/null
@@ -0,0 +1,84 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       case00-expect.meta \
+       case01-expect.meta \
+       case02-expect.meta \
+       case03-expect.meta \
+       case04-expect.meta \
+       case05-expect.meta \
+       case06-expect.meta \
+       case07-expect.meta \
+       case08-expect.meta \
+       case09-expect.meta \
+       case10-expect.meta \
+       case11-expect.meta \
+       case12-expect.meta \
+       case13-expect.meta \
+       case14-expect.meta \
+       case15-expect.meta \
+       case16-expect.meta \
+       case17-expect.meta \
+       case18-expect.meta \
+       case19-expect.meta \
+       case20-expect.meta \
+       case21-expect.meta \
+       case22-expect.meta \
+       case23-expect.meta \
+       case24-expect.meta \
+       case25-expect.meta \
+       case26-expect.meta \
+       case27-expect.meta \
+       case28-expect.meta \
+       case29-expect.meta \
+       case30-expect.meta \
+       case31-expect.meta \
+       case32-expect.meta \
+       case33-expect.meta \
+       case34-expect.meta \
+       case35-expect.meta \
+       case36-expect.meta \
+       case37-expect.meta \
+       case38-expect.meta \
+       case39-expect.meta \
+       case40-expect.meta \
+       case41-expect.meta \
+       case42-expect.meta \
+       case43-expect.meta \
+       case44-expect.meta \
+       case45-expect.meta \
+       case46-expect.meta \
+       case47-expect.meta \
+       case48-expect.meta \
+       case49-expect.meta \
+       case50-expect.meta \
+       case51-expect.meta \
+       case52-expect.meta \
+       case53-expect.meta \
+       case54-expect.meta \
+       case55-expect.meta \
+       case56-expect.meta \
+       case57-expect.meta \
+       case58-expect.meta \
+       case59-expect.meta \
+       case60-expect.meta \
+       case61-expect.meta \
+       case62-expect.meta
+
+clean-local:
+       -rm -f out.*
diff --git a/test/metaflac-test-files/case00-expect.meta b/test/metaflac-test-files/case00-expect.meta
new file mode 100644 (file)
index 0000000..1799092
--- /dev/null
@@ -0,0 +1,24 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 8192
diff --git a/test/metaflac-test-files/case01-expect.meta b/test/metaflac-test-files/case01-expect.meta
new file mode 100644 (file)
index 0000000..bae8f49
--- /dev/null
@@ -0,0 +1,9 @@
+a042237c5493fdb9656b94a83608d11a
+1152
+1152
+10
+10
+8000
+1
+8
+80000
diff --git a/test/metaflac-test-files/case02-expect.meta b/test/metaflac-test-files/case02-expect.meta
new file mode 100644 (file)
index 0000000..1b41bc3
--- /dev/null
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: 8192
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 12345
diff --git a/test/metaflac-test-files/case03-expect.meta b/test/metaflac-test-files/case03-expect.meta
new file mode 100644 (file)
index 0000000..e162757
--- /dev/null
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 93
+  comments: 1
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20488
diff --git a/test/metaflac-test-files/case04-expect.meta b/test/metaflac-test-files/case04-expect.meta
new file mode 100644 (file)
index 0000000..d8384c8
--- /dev/null
@@ -0,0 +1,26 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 2
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20464
diff --git a/test/metaflac-test-files/case05-expect.meta b/test/metaflac-test-files/case05-expect.meta
new file mode 100644 (file)
index 0000000..5017faa
--- /dev/null
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 132
+  comments: 3
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+    comment[2]: ARTIST=Vern
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20449
diff --git a/test/metaflac-test-files/case06-expect.meta b/test/metaflac-test-files/case06-expect.meta
new file mode 100644 (file)
index 0000000..7fbbe4b
--- /dev/null
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 166
+  comments: 4
+    comment[0]: ARTIST=The_artist_formerly_known_as_the_artist...
+    comment[1]: ARTIST=Chuck_Woolery
+    comment[2]: ARTIST=Vern
+    comment[3]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20415
diff --git a/test/metaflac-test-files/case07-expect.meta b/test/metaflac-test-files/case07-expect.meta
new file mode 100644 (file)
index 0000000..00160bf
--- /dev/null
@@ -0,0 +1,4 @@
+reference libFLAC 1.2.1 20070917
+ARTIST=The_artist_formerly_known_as_the_artist...
+ARTIST=Chuck_Woolery
+ARTIST=Vern
diff --git a/test/metaflac-test-files/case08-expect.meta b/test/metaflac-test-files/case08-expect.meta
new file mode 100644 (file)
index 0000000..e072ef6
--- /dev/null
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 113
+  comments: 3
+    comment[0]: ARTIST=Chuck_Woolery
+    comment[1]: ARTIST=Vern
+    comment[2]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20468
diff --git a/test/metaflac-test-files/case09-expect.meta b/test/metaflac-test-files/case09-expect.meta
new file mode 100644 (file)
index 0000000..db4702d
--- /dev/null
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20507
diff --git a/test/metaflac-test-files/case10-expect.meta b/test/metaflac-test-files/case10-expect.meta
new file mode 100644 (file)
index 0000000..c5986ab
--- /dev/null
@@ -0,0 +1,6 @@
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
diff --git a/test/metaflac-test-files/case11-expect.meta b/test/metaflac-test-files/case11-expect.meta
new file mode 100644 (file)
index 0000000..f42d320
--- /dev/null
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case12-expect.meta b/test/metaflac-test-files/case12-expect.meta
new file mode 100644 (file)
index 0000000..19ed454
--- /dev/null
@@ -0,0 +1,12 @@
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
diff --git a/test/metaflac-test-files/case13-expect.meta b/test/metaflac-test-files/case13-expect.meta
new file mode 100644 (file)
index 0000000..00804e1
--- /dev/null
@@ -0,0 +1,10 @@
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20507
diff --git a/test/metaflac-test-files/case14-expect.meta b/test/metaflac-test-files/case14-expect.meta
new file mode 100644 (file)
index 0000000..5e829ed
--- /dev/null
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20507
diff --git a/test/metaflac-test-files/case15-expect.meta b/test/metaflac-test-files/case15-expect.meta
new file mode 100644 (file)
index 0000000..d4be503
--- /dev/null
@@ -0,0 +1,16 @@
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 20507
diff --git a/test/metaflac-test-files/case16-expect.meta b/test/metaflac-test-files/case16-expect.meta
new file mode 100644 (file)
index 0000000..481d919
--- /dev/null
@@ -0,0 +1,33 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: 20507
+METADATA block #4
+  type: 1 (PADDING)
+  is last: false
+  length: 4321
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 4321
diff --git a/test/metaflac-test-files/case17-expect.meta b/test/metaflac-test-files/case17-expect.meta
new file mode 100644 (file)
index 0000000..49a220d
--- /dev/null
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 29157
diff --git a/test/metaflac-test-files/case18-expect.meta b/test/metaflac-test-files/case18-expect.meta
new file mode 100644 (file)
index 0000000..963cbdb
--- /dev/null
@@ -0,0 +1,29 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: 29157
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 0
diff --git a/test/metaflac-test-files/case19-expect.meta b/test/metaflac-test-files/case19-expect.meta
new file mode 100644 (file)
index 0000000..0eee4f0
--- /dev/null
@@ -0,0 +1,25 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 29161
diff --git a/test/metaflac-test-files/case20-expect.meta b/test/metaflac-test-files/case20-expect.meta
new file mode 100644 (file)
index 0000000..201b403
--- /dev/null
@@ -0,0 +1,29 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 74
+  comments: 1
+    comment[0]: TITLE=He_who_smelt_it_dealt_it
+METADATA block #3
+  type: 1 (PADDING)
+  is last: false
+  length: 29161
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 0
diff --git a/test/metaflac-test-files/case21-expect.meta b/test/metaflac-test-files/case21-expect.meta
new file mode 100644 (file)
index 0000000..dfb9441
--- /dev/null
@@ -0,0 +1,24 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 29199
diff --git a/test/metaflac-test-files/case22-expect.meta b/test/metaflac-test-files/case22-expect.meta
new file mode 100644 (file)
index 0000000..ed4af29
--- /dev/null
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 29199
diff --git a/test/metaflac-test-files/case23-expect.meta b/test/metaflac-test-files/case23-expect.meta
new file mode 100644 (file)
index 0000000..ed4af29
--- /dev/null
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 29199
diff --git a/test/metaflac-test-files/case24-expect.meta b/test/metaflac-test-files/case24-expect.meta
new file mode 100644 (file)
index 0000000..ed4af29
--- /dev/null
@@ -0,0 +1,18 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 29199
diff --git a/test/metaflac-test-files/case25-expect.meta b/test/metaflac-test-files/case25-expect.meta
new file mode 100644 (file)
index 0000000..8986a70
--- /dev/null
@@ -0,0 +1,14 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: 40
+  comments: 0
diff --git a/test/metaflac-test-files/case26-expect.meta b/test/metaflac-test-files/case26-expect.meta
new file mode 100644 (file)
index 0000000..eaf6c27
--- /dev/null
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 40
+  comments: 0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: false
+  length: 0
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 0
diff --git a/test/metaflac-test-files/case27-expect.meta b/test/metaflac-test-files/case27-expect.meta
new file mode 100644 (file)
index 0000000..eac969c
--- /dev/null
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 1 (PADDING)
+  is last: true
+  length: 48
diff --git a/test/metaflac-test-files/case28-expect.meta b/test/metaflac-test-files/case28-expect.meta
new file mode 100644 (file)
index 0000000..eac969c
--- /dev/null
@@ -0,0 +1,13 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 1 (PADDING)
+  is last: true
+  length: 48
diff --git a/test/metaflac-test-files/case29-expect.meta b/test/metaflac-test-files/case29-expect.meta
new file mode 100644 (file)
index 0000000..cd0ad27
--- /dev/null
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: true
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case30-expect.meta b/test/metaflac-test-files/case30-expect.meta
new file mode 100644 (file)
index 0000000..cd0ad27
--- /dev/null
@@ -0,0 +1,9 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: true
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
diff --git a/test/metaflac-test-files/case31-expect.meta b/test/metaflac-test-files/case31-expect.meta
new file mode 100644 (file)
index 0000000..a8fb438
--- /dev/null
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: 66
+  comments: 1
+    comment[0]: f=0123456789abcdefghij
diff --git a/test/metaflac-test-files/case32-expect.meta b/test/metaflac-test-files/case32-expect.meta
new file mode 100644 (file)
index 0000000..9d1a184
--- /dev/null
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: 65
+  comments: 1
+    comment[0]: f=0123456789abcdefghi
diff --git a/test/metaflac-test-files/case33-expect.meta b/test/metaflac-test-files/case33-expect.meta
new file mode 100644 (file)
index 0000000..0c883c3
--- /dev/null
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 61
+  comments: 1
+    comment[0]: f=0123456789abcde
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 0
diff --git a/test/metaflac-test-files/case34-expect.meta b/test/metaflac-test-files/case34-expect.meta
new file mode 100644 (file)
index 0000000..b59ccb8
--- /dev/null
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 47
+  comments: 1
+    comment[0]: f=0
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 14
diff --git a/test/metaflac-test-files/case35-expect.meta b/test/metaflac-test-files/case35-expect.meta
new file mode 100644 (file)
index 0000000..7f48452
--- /dev/null
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 56
+  comments: 1
+    comment[0]: f=0123456789
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case36-expect.meta b/test/metaflac-test-files/case36-expect.meta
new file mode 100644 (file)
index 0000000..9d1a184
--- /dev/null
@@ -0,0 +1,15 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: true
+  length: 65
+  comments: 1
+    comment[0]: f=0123456789abcdefghi
diff --git a/test/metaflac-test-files/case37-expect.meta b/test/metaflac-test-files/case37-expect.meta
new file mode 100644 (file)
index 0000000..7f48452
--- /dev/null
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 56
+  comments: 1
+    comment[0]: f=0123456789
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case38-expect.meta b/test/metaflac-test-files/case38-expect.meta
new file mode 100644 (file)
index 0000000..93d1e32
--- /dev/null
@@ -0,0 +1,19 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 66
+  comments: 1
+    comment[0]: f=0123456789abcdefghij
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case39-expect.meta b/test/metaflac-test-files/case39-expect.meta
new file mode 100644 (file)
index 0000000..700caff
--- /dev/null
@@ -0,0 +1,20 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 82
+  comments: 2
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case40-expect.meta b/test/metaflac-test-files/case40-expect.meta
new file mode 100644 (file)
index 0000000..125eedc
--- /dev/null
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case41-expect.meta b/test/metaflac-test-files/case41-expect.meta
new file mode 100644 (file)
index 0000000..bf71afc
--- /dev/null
@@ -0,0 +1,27 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 300
+  comments: 9
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+    comment[4]: REPLAYGAIN_REFERENCE_LOUDNESS=89.0 dB
+    comment[5]: REPLAYGAIN_TRACK_GAIN=+64.82 dB
+    comment[6]: REPLAYGAIN_TRACK_PEAK=0.00000000
+    comment[7]: REPLAYGAIN_ALBUM_GAIN=+64.82 dB
+    comment[8]: REPLAYGAIN_ALBUM_PEAK=0.00000000
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 5
diff --git a/test/metaflac-test-files/case42-expect.meta b/test/metaflac-test-files/case42-expect.meta
new file mode 100644 (file)
index 0000000..8973972
--- /dev/null
@@ -0,0 +1,22 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #2
+  type: 1 (PADDING)
+  is last: true
+  length: 188
diff --git a/test/metaflac-test-files/case43-expect.meta b/test/metaflac-test-files/case43-expect.meta
new file mode 100644 (file)
index 0000000..bf9fe5e
--- /dev/null
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 188
diff --git a/test/metaflac-test-files/case44-expect.meta b/test/metaflac-test-files/case44-expect.meta
new file mode 100644 (file)
index 0000000..229b435
--- /dev/null
@@ -0,0 +1,28 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 1 (PADDING)
+  is last: true
+  length: 672
diff --git a/test/metaflac-test-files/case45-expect.meta b/test/metaflac-test-files/case45-expect.meta
new file mode 100644 (file)
index 0000000..bf9fe5e
--- /dev/null
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 188
diff --git a/test/metaflac-test-files/case46-expect.meta b/test/metaflac-test-files/case46-expect.meta
new file mode 100644 (file)
index 0000000..1d565e1
--- /dev/null
@@ -0,0 +1,62 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case47-expect.meta b/test/metaflac-test-files/case47-expect.meta
new file mode 100644 (file)
index 0000000..e122cf7
--- /dev/null
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case48-expect.meta b/test/metaflac-test-files/case48-expect.meta
new file mode 100644 (file)
index 0000000..6768710
--- /dev/null
@@ -0,0 +1,88 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case49-expect.meta b/test/metaflac-test-files/case49-expect.meta
new file mode 100644 (file)
index 0000000..9ddfff2
--- /dev/null
@@ -0,0 +1,101 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case50-expect.meta b/test/metaflac-test-files/case50-expect.meta
new file mode 100644 (file)
index 0000000..ea64964
--- /dev/null
@@ -0,0 +1,114 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case51-expect.meta b/test/metaflac-test-files/case51-expect.meta
new file mode 100644 (file)
index 0000000..b73bb68
--- /dev/null
@@ -0,0 +1,127 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case52-expect.meta b/test/metaflac-test-files/case52-expect.meta
new file mode 100644 (file)
index 0000000..ee3da3c
--- /dev/null
@@ -0,0 +1,140 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case53-expect.meta b/test/metaflac-test-files/case53-expect.meta
new file mode 100644 (file)
index 0000000..13d9844
--- /dev/null
@@ -0,0 +1,153 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case54-expect.meta b/test/metaflac-test-files/case54-expect.meta
new file mode 100644 (file)
index 0000000..ff6e4ef
--- /dev/null
@@ -0,0 +1,166 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case55-expect.meta b/test/metaflac-test-files/case55-expect.meta
new file mode 100644 (file)
index 0000000..a829c51
--- /dev/null
@@ -0,0 +1,179 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: 1846
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1800
+  data:
+METADATA block #14
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case56-expect.meta b/test/metaflac-test-files/case56-expect.meta
new file mode 100644 (file)
index 0000000..095e1dd
--- /dev/null
@@ -0,0 +1,192 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: 1846
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1800
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: 1862
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1816
+  data:
+METADATA block #15
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case57-expect.meta b/test/metaflac-test-files/case57-expect.meta
new file mode 100644 (file)
index 0000000..95043e0
--- /dev/null
@@ -0,0 +1,205 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: 1846
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1800
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: 1862
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1816
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: 589
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: 543
+  data:
+METADATA block #16
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case58-expect.meta b/test/metaflac-test-files/case58-expect.meta
new file mode 100644 (file)
index 0000000..6f14174
--- /dev/null
@@ -0,0 +1,218 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: 1846
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1800
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: 1862
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1816
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: 589
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: 543
+  data:
+METADATA block #16
+  type: 6 (PICTURE)
+  is last: false
+  length: 605
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 7.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: 559
+  data:
+METADATA block #17
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case59-expect.meta b/test/metaflac-test-files/case59-expect.meta
new file mode 100644 (file)
index 0000000..f68d011
--- /dev/null
@@ -0,0 +1,231 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 141
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 0.gif
+  width: 24
+  height: 24
+  depth: 24
+  colors: 2
+  data length: 95
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 917
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 1.gif
+  width: 12
+  height: 8
+  depth: 24
+  colors: 256
+  data length: 871
+  data:
+METADATA block #6
+  type: 6 (PICTURE)
+  is last: false
+  length: 578
+  type: 3 (Cover (front))
+  MIME type: image/gif
+  description: 2.gif
+  width: 16
+  height: 14
+  depth: 24
+  colors: 128
+  data length: 532
+  data:
+METADATA block #7
+  type: 6 (PICTURE)
+  is last: false
+  length: 377
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 0.jpg
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 330
+  data:
+METADATA block #8
+  type: 6 (PICTURE)
+  is last: false
+  length: 614
+  type: 4 (Cover (back))
+  MIME type: image/jpeg
+  description: 4.jpg
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 567
+  data:
+METADATA block #9
+  type: 6 (PICTURE)
+  is last: false
+  length: 492
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 0.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #10
+  type: 6 (PICTURE)
+  is last: false
+  length: 508
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 1.png
+  width: 30
+  height: 20
+  depth: 8
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #11
+  type: 6 (PICTURE)
+  is last: false
+  length: 338
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 2.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 292
+  data:
+METADATA block #12
+  type: 6 (PICTURE)
+  is last: false
+  length: 354
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 3.png
+  width: 30
+  height: 20
+  depth: 24
+  colors: 7
+  data length: 308
+  data:
+METADATA block #13
+  type: 6 (PICTURE)
+  is last: false
+  length: 1846
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 4.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1800
+  data:
+METADATA block #14
+  type: 6 (PICTURE)
+  is last: false
+  length: 1862
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 5.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 1816
+  data:
+METADATA block #15
+  type: 6 (PICTURE)
+  is last: false
+  length: 589
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 6.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: 543
+  data:
+METADATA block #16
+  type: 6 (PICTURE)
+  is last: false
+  length: 605
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 7.png
+  width: 31
+  height: 47
+  depth: 24
+  colors: 23
+  data length: 559
+  data:
+METADATA block #17
+  type: 6 (PICTURE)
+  is last: false
+  length: 290
+  type: 5 (Leaflet page)
+  MIME type: image/png
+  description: 8.png
+  width: 32
+  height: 32
+  depth: 32
+  colors: 0 (unindexed)
+  data length: 244
+  data:
+METADATA block #18
+  type: 1 (PADDING)
+  is last: true
+  length: 43
diff --git a/test/metaflac-test-files/case60-expect.meta b/test/metaflac-test-files/case60-expect.meta
new file mode 100644 (file)
index 0000000..b085aa0
--- /dev/null
@@ -0,0 +1,49 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 1 (PADDING)
+  is last: true
+  length: 9610
diff --git a/test/metaflac-test-files/case61-expect.meta b/test/metaflac-test-files/case61-expect.meta
new file mode 100644 (file)
index 0000000..6c315d8
--- /dev/null
@@ -0,0 +1,62 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 500
+  type: 1 (32x32 pixels 'file icon' (PNG only))
+  MIME type: image/png
+  description: standard_icon
+  width: 32
+  height: 32
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #5
+  type: 1 (PADDING)
+  is last: true
+  length: 9106
diff --git a/test/metaflac-test-files/case62-expect.meta b/test/metaflac-test-files/case62-expect.meta
new file mode 100644 (file)
index 0000000..5b64e62
--- /dev/null
@@ -0,0 +1,75 @@
+METADATA block #0
+  type: 0 (STREAMINFO)
+  is last: false
+  length: 34
+  sample_rate: 8000 Hz
+  channels: 1
+  bits-per-sample: 8
+  total samples: 80000
+  MD5 signature: a042237c5493fdb9656b94a83608d11a
+METADATA block #1
+  type: 3 (SEEKTABLE)
+  is last: false
+  length: 18
+  seek points: 1
+    point 0: sample_number=0
+METADATA block #2
+  type: 4 (VORBIS_COMMENT)
+  is last: false
+  length: 117
+  comments: 4
+    comment[0]: f=0123456789abcdefghij
+    comment[1]: TITLE=Tittle
+    comment[2]: artist=Fartist
+    comment[3]: artist=artits
+METADATA block #3
+  type: 5 (CUESHEET)
+  is last: false
+  length: 480
+  media catalog number: 1234567890123
+  lead-in: 0
+  is CD: false
+  number of tracks: 2
+    track[0]
+      offset: 0
+      number: 1
+      ISRC: 
+      type: AUDIO
+      pre-emphasis: false
+      number of index points: 1
+        index[0]
+          offset: 0
+          number: 1
+    track[1]
+      offset: 80000
+      number: 255 (LEAD-OUT)
+METADATA block #4
+  type: 6 (PICTURE)
+  is last: false
+  length: 500
+  type: 1 (32x32 pixels 'file icon' (PNG only))
+  MIME type: image/png
+  description: standard_icon
+  width: 32
+  height: 32
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 446
+  data:
+METADATA block #5
+  type: 6 (PICTURE)
+  is last: false
+  length: 507
+  type: 2 (Other file icon)
+  MIME type: image/png
+  description: icon
+  width: 64
+  height: 64
+  depth: 24
+  colors: 0 (unindexed)
+  data length: 462
+  data:
+METADATA block #6
+  type: 1 (PADDING)
+  is last: true
+  length: 8595
diff --git a/test/metaflac.flac.in b/test/metaflac.flac.in
new file mode 100644 (file)
index 0000000..7989263
Binary files /dev/null and b/test/metaflac.flac.in differ
diff --git a/test/metaflac.flac.ok b/test/metaflac.flac.ok
new file mode 100644 (file)
index 0000000..82ad84c
Binary files /dev/null and b/test/metaflac.flac.ok differ
diff --git a/test/picture.ok b/test/picture.ok
new file mode 100644 (file)
index 0000000..4b7e55d
--- /dev/null
@@ -0,0 +1,42 @@
+
++++ grabbag unit test: picture
+
+testing grabbag__picture_parse_specification("")... OK (failed as expected, error: error opening picture file)
+testing grabbag__picture_parse_specification("||||")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|||")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|desc|320|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240x9|")... OK (failed as expected: error opening picture file)
+testing grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif")... OK (failed as expected: invalid picture specification: can't parse resolution/color part)
+testing grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif")... OK (failed as expected: type 1 icon must be a 32x32 pixel PNG)
+testing grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif")... OK (failed as expected: unable to extract resolution and color info from URL, user must set explicitly)
+testing grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif")... OK
+testing grabbag__picture_parse_specification("pictures/0.gif")... OK
+testing grabbag__picture_parse_specification("pictures/1.gif")... OK
+testing grabbag__picture_parse_specification("pictures/2.gif")... OK
+testing grabbag__picture_parse_specification("pictures/0.jpg")... OK
+testing grabbag__picture_parse_specification("pictures/4.jpg")... OK
+testing grabbag__picture_parse_specification("pictures/0.png")... OK
+testing grabbag__picture_parse_specification("pictures/1.png")... OK
+testing grabbag__picture_parse_specification("pictures/2.png")... OK
+testing grabbag__picture_parse_specification("pictures/3.png")... OK
+testing grabbag__picture_parse_specification("pictures/4.png")... OK
+testing grabbag__picture_parse_specification("pictures/5.png")... OK
+testing grabbag__picture_parse_specification("pictures/6.png")... OK
+testing grabbag__picture_parse_specification("pictures/7.png")... OK
+testing grabbag__picture_parse_specification("pictures/8.png")... OK
+testing grabbag__picture_parse_specification("3|image/gif|||pictures/0.gif")... OK
+testing grabbag__picture_parse_specification("4|image/gif|||pictures/1.gif")... OK
+testing grabbag__picture_parse_specification("0|image/gif|||pictures/2.gif")... OK
+testing grabbag__picture_parse_specification("3|image/jpeg|||pictures/0.jpg")... OK
+testing grabbag__picture_parse_specification("3|image/jpeg|||pictures/4.jpg")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/0.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/1.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/2.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/3.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/4.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/5.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/6.png")... OK
+testing grabbag__picture_parse_specification("3|image/png|||pictures/7.png")... OK
+testing grabbag__picture_parse_specification("999|image/png|||pictures/8.png")... OK
+testing grabbag__picture_parse_specification("3|image/gif||320x240x3/2|pictures/0.gif")... OK
diff --git a/test/pictures/0.gif b/test/pictures/0.gif
new file mode 100644 (file)
index 0000000..c9f3d71
Binary files /dev/null and b/test/pictures/0.gif differ
diff --git a/test/pictures/0.jpg b/test/pictures/0.jpg
new file mode 100644 (file)
index 0000000..54b9a7c
Binary files /dev/null and b/test/pictures/0.jpg differ
diff --git a/test/pictures/0.png b/test/pictures/0.png
new file mode 100644 (file)
index 0000000..2f3ec80
Binary files /dev/null and b/test/pictures/0.png differ
diff --git a/test/pictures/1.gif b/test/pictures/1.gif
new file mode 100644 (file)
index 0000000..c40eeae
Binary files /dev/null and b/test/pictures/1.gif differ
diff --git a/test/pictures/1.png b/test/pictures/1.png
new file mode 100644 (file)
index 0000000..2b487c0
Binary files /dev/null and b/test/pictures/1.png differ
diff --git a/test/pictures/2.gif b/test/pictures/2.gif
new file mode 100644 (file)
index 0000000..632098b
Binary files /dev/null and b/test/pictures/2.gif differ
diff --git a/test/pictures/2.png b/test/pictures/2.png
new file mode 100644 (file)
index 0000000..a7ca42b
Binary files /dev/null and b/test/pictures/2.png differ
diff --git a/test/pictures/3.png b/test/pictures/3.png
new file mode 100644 (file)
index 0000000..9d117b6
Binary files /dev/null and b/test/pictures/3.png differ
diff --git a/test/pictures/4.jpg b/test/pictures/4.jpg
new file mode 100644 (file)
index 0000000..da78796
Binary files /dev/null and b/test/pictures/4.jpg differ
diff --git a/test/pictures/4.png b/test/pictures/4.png
new file mode 100644 (file)
index 0000000..72c0a45
Binary files /dev/null and b/test/pictures/4.png differ
diff --git a/test/pictures/5.png b/test/pictures/5.png
new file mode 100644 (file)
index 0000000..abefad5
Binary files /dev/null and b/test/pictures/5.png differ
diff --git a/test/pictures/6.png b/test/pictures/6.png
new file mode 100644 (file)
index 0000000..4953ceb
Binary files /dev/null and b/test/pictures/6.png differ
diff --git a/test/pictures/7.png b/test/pictures/7.png
new file mode 100644 (file)
index 0000000..c8934c1
Binary files /dev/null and b/test/pictures/7.png differ
diff --git a/test/pictures/8.png b/test/pictures/8.png
new file mode 100644 (file)
index 0000000..01e4118
Binary files /dev/null and b/test/pictures/8.png differ
diff --git a/test/pictures/Makefile.am b/test/pictures/Makefile.am
new file mode 100644 (file)
index 0000000..a93bd64
--- /dev/null
@@ -0,0 +1,32 @@
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+EXTRA_DIST = \
+       0.gif \
+       0.jpg \
+       0.png \
+       1.gif \
+       1.png \
+       2.gif \
+       2.png \
+       3.png \
+       4.jpg \
+       4.png \
+       5.png \
+       6.png \
+       7.png \
+       8.png
diff --git a/test/test_bins.sh b/test/test_bins.sh
new file mode 100755 (executable)
index 0000000..dc12890
--- /dev/null
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/utf8/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/flac:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+BINS_PATH=../../test_files/bins
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+       FLAC__TEST_LEVEL=1
+fi
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_bins.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 flac $* 4>>test_bins.valgrind.log
+       else
+               flac $*
+       fi
+}
+
+test -d ${BINS_PATH} || exit 77
+
+test_file ()
+{
+       name=$1
+       channels=$2
+       bps=$3
+       encode_options="$4"
+
+       echo -n "$name.bin (--channels=$channels --bps=$bps $encode_options): encode..."
+       cmd="run_flac --verify --silent --force --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding $name.bin"
+       echo "### ENCODE $name #######################################################" >> ./streams.log
+       echo "###    cmd=$cmd" >> ./streams.log
+       $cmd 2>>./streams.log || die "ERROR during encode of $name"
+
+       echo -n "decode..."
+       cmd="run_flac --silent --force --endian=big --sign=signed --decode --force-raw-format $name.flac";
+       echo "### DECODE $name #######################################################" >> ./streams.log
+       echo "###    cmd=$cmd" >> ./streams.log
+       $cmd 2>>./streams.log || die "ERROR during decode of $name"
+
+       ls -1l $name.bin >> ./streams.log
+       ls -1l $name.flac >> ./streams.log
+       ls -1l $name.raw >> ./streams.log
+
+       echo -n "compare..."
+       cmp $name.bin $name.raw || die "ERROR during compare of $name"
+
+       echo OK
+}
+
+echo "Testing bins..."
+for f in b00 b01 b02 b03 b04 ; do
+       binfile=$BINS_PATH/$f
+       if [ -f $binfile.bin ] ; then
+               for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+                       for channels in 1 2 4 8 ; do
+                               for bps in 8 16 24 ; do
+                                       for opt in 0 1 2 4 5 6 8 ; do
+                                               for extras in '' '-p' '-e' ; do
+                                                       for blocksize in '' '--lax -b 32' '--lax -b 32768' '--lax -b 65535' ; do
+                                                               test_file $binfile $channels $bps "-$opt $extras $blocksize $disable"
+                                                       done
+                                               done
+                                       done
+                                       if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+                                               test_file $binfile $channels $bps "--lax -b 16384 -m -r 8 -l 32 -e -p $disable"
+                                       fi
+                               done
+                       done
+               done
+       else
+               echo "$binfile not found, skipping."
+       fi
+done
diff --git a/test/test_flac.sh b/test/test_flac.sh
new file mode 100755 (executable)
index 0000000..e19cc03
--- /dev/null
@@ -0,0 +1,1190 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+dddie="die ERROR: creating files with dd"
+
+if [ x = x"$1" ] ; then
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+# change to 'false' to show flac output (useful for debugging)
+if true ; then
+       SILENT='--silent'
+       TOTALLY_SILENT='--totally-silent'
+else
+       SILENT=''
+       TOTALLY_SILENT=''
+fi
+
+LD_LIBRARY_PATH=`pwd`/../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/utf8/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=`pwd`/../src/flac:$PATH
+PATH=`pwd`/../src/metaflac:$PATH
+PATH=`pwd`/../src/test_streams:$PATH
+PATH=`pwd`/../obj/$BUILD/bin:$PATH
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_flac.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 flac $* 4>>test_flac.valgrind.log
+       else
+               flac $*
+       fi
+}
+
+run_metaflac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 metaflac $*" >>test_flac.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 metaflac $* 4>>test_flac.valgrind.log
+       else
+               metaflac $*
+       fi
+}
+
+md5cmp ()
+{
+       #n=`( [ -f "$1" ] && [ -f "$2" ] && metaflac --show-md5sum --no-filename "$1" "$2" 2>/dev/null || die "ERROR: comparing FLAC files $1 and $2 by MD5 sum" ) | uniq | wc -l`
+       n=`( [ -f "$1" ] && [ -f "$2" ] && metaflac --show-md5sum --no-filename "$1" "$2" 2>/dev/null || exit 1 ) | uniq | wc -l`
+       [ "$n" != "" ] && [ $n = 1 ]
+}
+
+if [ `env | grep -ic '^comspec='` != 0 ] ; then
+       is_win=yes
+else
+       is_win=no
+fi
+
+echo "Checking for --ogg support in flac..."
+if flac --ogg $SILENT --force-raw-format --endian=little --sign=signed --channels=1 --bps=8 --sample-rate=44100 -c $0 1>/dev/null 2>&1 ; then
+       has_ogg=yes;
+       echo "flac --ogg works"
+else
+       has_ogg=no;
+       echo "flac --ogg doesn't work"
+fi
+
+echo "Generating streams..."
+if [ ! -f wacky1.wav ] ; then
+       test_streams || die "ERROR during test_streams"
+fi
+
+############################################################################
+# test that flac doesn't automatically overwrite files unless -f is used
+############################################################################
+
+echo "Try encoding to a file that exists; should fail"
+cp wacky1.wav exist.wav
+touch exist.flac
+if run_flac $TOTALLY_SILENT -0 exist.wav ; then
+       die "ERROR: it should have failed but didn't"
+else
+       echo "OK, it failed as it should"
+fi
+
+echo "Try encoding with -f to a file that exists; should succeed"
+if run_flac $TOTALLY_SILENT -0 --force exist.wav ; then
+       echo "OK, it succeeded as it should"
+else
+       die "ERROR: it should have succeeded but didn't"
+fi
+
+echo "Try decoding to a file that exists; should fail"
+if run_flac $TOTALLY_SILENT -d exist.flac ; then
+       die "ERROR: it should have failed but didn't"
+else
+       echo "OK, it failed as it should"
+fi
+
+echo "Try decoding with -f to a file that exists; should succeed"
+if run_flac $TOTALLY_SILENT -d -f exist.flac ; then
+       echo "OK, it succeeded as it should"
+else
+       die "ERROR: it should have succeeded but didn't"
+fi
+
+rm -f exist.wav exist.flac
+
+############################################################################
+# test fractional block sizes
+############################################################################
+
+test_fractional ()
+{
+       blocksize=$1
+       samples=$2
+       dd if=noise.raw ibs=4 count=$samples of=pbs.raw 2>/dev/null || $dddie
+       echo -n "fractional block size test (blocksize=$blocksize samples=$samples) encode... "
+       run_flac $SILENT --force --verify --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=$blocksize --no-padding --lax -o pbs.flac pbs.raw || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --force-raw-format --endian=little --sign=signed -o pbs.cmp pbs.flac || die "ERROR"
+       echo -n "compare... "
+       cmp pbs.raw pbs.cmp || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f pbs.raw pbs.flac pbs.cmp
+}
+
+# The special significance of 2048 is it's the # of samples that flac calls
+# FLAC__stream_encoder_process() on.
+#
+# We're trying to make sure the 1-sample overread logic in the stream encoder
+# (used for last-block checking) works; these values probe around common
+# multiples of the flac sample chunk size (2048) and the blocksize.
+for samples in 31 32 33 34 35 2046 2047 2048 2049 2050 ; do
+       test_fractional 33 $samples
+done
+for samples in 254 255 256 257 258 510 511 512 513 514 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 ; do
+       test_fractional 256 $samples
+done
+for samples in 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 ; do
+       test_fractional 2048 $samples
+done
+for samples in 1022 1023 1024 1025 1026 2046 2047 2048 2049 2050 4094 4095 4096 4097 4098 4606 4607 4608 4609 4610 8190 8191 8192 8193 8194 16382 16383 16384 16385 16386 ; do
+       test_fractional 4608 $samples
+done
+
+############################################################################
+# basic 'round-trip' tests of various kinds of streams
+############################################################################
+
+rt_test_raw ()
+{
+       f="$1"
+       channels=`echo $f | awk -F- '{print $2}'`
+       bps=`echo $f | awk -F- '{print $3}'`
+       echo -n "round-trip test ($f) encode... "
+       run_flac $SILENT --force --verify --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels --no-padding --lax -o rt.flac $f || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --force-raw-format --endian=little --sign=signed -o rt.raw rt.flac || die "ERROR"
+       echo -n "compare... "
+       cmp $f rt.raw || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f rt.flac rt.raw
+}
+
+rt_test_wav ()
+{
+       f="$1"
+       echo -n "round-trip test ($f) encode... "
+       run_flac $SILENT --force --verify --channel-map=none --no-padding --lax -o rt.flac $f || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --channel-map=none -o rt.wav rt.flac || die "ERROR"
+       echo -n "compare... "
+       cmp $f rt.wav || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f rt.flac rt.wav
+}
+
+rt_test_aiff ()
+{
+       f="$1"
+       echo -n "round-trip test ($f) encode... "
+       run_flac $SILENT --force --verify --channel-map=none --no-padding --lax -o rt.flac $f || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --channel-map=none -o rt.aiff rt.flac || die "ERROR"
+       echo -n "compare... "
+       cmp $f rt.aiff || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f rt.flac rt.aiff
+}
+
+# assumes input file is WAVE; does not check the metadata-preserving features of flac-to-flac; that is checked later
+rt_test_flac ()
+{
+       f="$1"
+       echo -n "round-trip test ($f->flac->flac->wav) encode... "
+       run_flac $SILENT --force --verify --channel-map=none --no-padding --lax -o rt.flac $f || die "ERROR"
+       echo -n "re-encode... "
+       run_flac $SILENT --force --verify --lax -o rt2.flac rt.flac || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --channel-map=none -o rt.wav rt2.flac || die "ERROR"
+       echo -n "compare... "
+       cmp $f rt.wav || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f rt.wav rt.flac rt2.flac
+}
+
+# assumes input file is WAVE; does not check the metadata-preserving features of flac-to-flac; that is checked later
+rt_test_ogg_flac ()
+{
+       f="$1"
+       echo -n "round-trip test ($f->oggflac->oggflac->wav) encode... "
+       run_flac $SILENT --force --verify --channel-map=none --no-padding --lax -o rt.oga --ogg $f || die "ERROR"
+       echo -n "re-encode... "
+       run_flac $SILENT --force --verify --lax -o rt2.oga --ogg rt.oga || die "ERROR"
+       echo -n "decode... "
+       run_flac $SILENT --force --decode --channel-map=none -o rt.wav rt2.oga || die "ERROR"
+       echo -n "compare... "
+       cmp $f rt.wav || die "ERROR: file mismatch"
+       echo "OK"
+       rm -f rt.wav rt.oga rt2.oga
+}
+
+for f in rt-*.raw ; do
+       rt_test_raw $f
+done
+for f in rt-*.wav ; do
+       rt_test_wav $f
+done
+for f in rt-*.aiff ; do
+       rt_test_aiff $f
+done
+for f in rt-*.wav ; do
+       rt_test_flac $f
+done
+if [ $has_ogg = yes ] ; then
+       for f in rt-*.wav ; do
+               rt_test_ogg_flac $f
+       done
+fi
+
+############################################################################
+# test --skip and --until
+############################################################################
+
+#
+# first make some chopped-up raw files
+#
+echo "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMN" > master.raw
+dd if=master.raw ibs=1 count=50 of=50c.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=40 of=50c.skip10.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=11 count=39 of=50c.skip11.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=30 of=50c.skip20.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=30 count=20 of=50c.skip30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=40 count=10 of=50c.skip40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=10 of=50c.until10.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=20 of=50c.until20.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=30 of=50c.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=39 of=50c.until39.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 count=40 of=50c.until40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=20 of=50c.skip10.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=29 of=50c.skip10.until39.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=10 count=30 of=50c.skip10.until40.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=10 of=50c.skip20.until30.raw 2>/dev/null || $dddie
+dd if=master.raw ibs=1 skip=20 count=20 of=50c.skip20.until40.raw 2>/dev/null || $dddie
+
+wav_eopt="$SILENT --force --verify --no-padding --lax"
+wav_dopt="$SILENT --force --decode"
+
+raw_eopt="$wav_eopt --force-raw-format --endian=big --sign=signed --sample-rate=10 --bps=8 --channels=1"
+raw_dopt="$wav_dopt --force-raw-format --endian=big --sign=signed"
+
+#
+# convert them to WAVE/AIFF/Ogg FLAC files
+#
+convert_to_wav ()
+{
+       run_flac "$2" $1.raw || die "ERROR converting $1.raw to WAVE"
+       run_flac "$3" $1.flac || die "ERROR converting $1.raw to WAVE"
+}
+convert_to_wav 50c "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip11 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until10 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until20 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until39 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.until40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until39 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip10.until40 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20.until30 "$raw_eopt" "$wav_dopt"
+convert_to_wav 50c.skip20.until40 "$raw_eopt" "$wav_dopt"
+
+convert_to_aiff ()
+{
+       run_flac "$2" $1.raw || die "ERROR converting $1.raw to AIFF"
+       run_flac "$3" $1.flac -o $1.aiff || die "ERROR converting $1.raw to AIFF"
+}
+convert_to_aiff 50c "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip11 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until10 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until20 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until39 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.until40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until39 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip10.until40 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20.until30 "$raw_eopt" "$wav_dopt"
+convert_to_aiff 50c.skip20.until40 "$raw_eopt" "$wav_dopt"
+
+convert_to_ogg ()
+{
+       run_flac "$wav_eopt" --ogg $1.wav || die "ERROR converting $1.raw to Ogg FLAC"
+}
+if [ $has_ogg = yes ] ; then
+       convert_to_ogg 50c
+       convert_to_ogg 50c.skip10
+       convert_to_ogg 50c.skip11
+       convert_to_ogg 50c.skip20
+       convert_to_ogg 50c.skip30
+       convert_to_ogg 50c.skip40
+       convert_to_ogg 50c.until10
+       convert_to_ogg 50c.until20
+       convert_to_ogg 50c.until30
+       convert_to_ogg 50c.until39
+       convert_to_ogg 50c.until40
+       convert_to_ogg 50c.skip10.until30
+       convert_to_ogg 50c.skip10.until39
+       convert_to_ogg 50c.skip10.until40
+       convert_to_ogg 50c.skip20.until30
+       convert_to_ogg 50c.skip20.until40
+fi
+
+test_skip_until ()
+{
+       in_fmt=$1
+       out_fmt=$2
+
+       [ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
+
+       [ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
+
+       if [ $in_fmt = raw ] ; then
+               eopt="$raw_eopt"
+               dopt="$raw_dopt"
+       else
+               eopt="$wav_eopt"
+               dopt="$wav_dopt"
+       fi
+
+       if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
+               CMP=md5cmp
+       else
+               CMP=cmp
+       fi
+
+       if [ $out_fmt = ogg ] ; then
+               eopt="--ogg $eopt"
+       fi
+
+       #
+       # test --skip when encoding
+       #
+
+       desc="($in_fmt<->$out_fmt)"
+
+       echo -n "testing --skip=# (encode) $desc... "
+       run_flac $eopt --skip=10 -o z50c.skip10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.$in_fmt z50c.skip10.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.skip10.$in_fmt || die "ERROR: file mismatch for --skip=10 (encode) $desc"
+       rm -f z50c.skip10.$out_fmt z50c.skip10.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=mm:ss (encode) $desc... "
+       run_flac $eopt --skip=0:01 -o z50c.skip0:01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip0:01.$in_fmt z50c.skip0:01.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.skip0:01.$in_fmt || die "ERROR: file mismatch for --skip=0:01 (encode) $desc"
+       rm -f z50c.skip0:01.$out_fmt z50c.skip0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=mm:ss.sss (encode) $desc... "
+       run_flac $eopt --skip=0:01.1001 -o z50c.skip0:01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip0:01.1001.$in_fmt z50c.skip0:01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip11.$in_fmt z50c.skip0:01.1001.$in_fmt || die "ERROR: file mismatch for --skip=0:01.1001 (encode) $desc"
+       rm -f z50c.skip0:01.1001.$out_fmt z50c.skip0:01.1001.$in_fmt
+       echo OK
+
+       #
+       # test --skip when decoding
+       #
+
+       if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+       echo -n "testing --skip=# (decode) $desc... "
+       run_flac $dopt --skip=10 -o z50c.skip10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.skip10.$in_fmt || die "ERROR: file mismatch for --skip=10 (decode) $desc"
+       rm -f z50c.skip10.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=mm:ss (decode) $desc... "
+       run_flac $dopt --skip=0:01 -o z50c.skip0:01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.skip0:01.$in_fmt || die "ERROR: file mismatch for --skip=0:01 (decode) $desc"
+       rm -f z50c.skip0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=mm:ss.sss (decode) $desc... "
+       run_flac $dopt --skip=0:01.1001 -o z50c.skip0:01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip11.$in_fmt z50c.skip0:01.1001.$in_fmt || die "ERROR: file mismatch for --skip=0:01.1001 (decode) $desc"
+       rm -f z50c.skip0:01.1001.$in_fmt
+       echo OK
+
+       rm -f z50c.$out_fmt
+
+       #
+       # test --until when encoding
+       #
+
+       echo -n "testing --until=# (encode) $desc... "
+       run_flac $eopt --until=40 -o z50c.until40.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until40.$in_fmt z50c.until40.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until40.$in_fmt || die "ERROR: file mismatch for --until=40 (encode) $desc"
+       rm -f z50c.until40.$out_fmt z50c.until40.$in_fmt
+       echo OK
+
+       echo -n "testing --until=mm:ss (encode) $desc... "
+       run_flac $eopt --until=0:04 -o z50c.until0:04.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until0:04.$in_fmt z50c.until0:04.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until0:04.$in_fmt || die "ERROR: file mismatch for --until=0:04 (encode) $desc"
+       rm -f z50c.until0:04.$out_fmt z50c.until0:04.$in_fmt
+       echo OK
+
+       echo -n "testing --until=mm:ss.sss (encode) $desc... "
+       run_flac $eopt --until=0:03.9001 -o z50c.until0:03.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until0:03.9001.$in_fmt z50c.until0:03.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until39.$in_fmt z50c.until0:03.9001.$in_fmt || die "ERROR: file mismatch for --until=0:03.9001 (encode) $desc"
+       rm -f z50c.until0:03.9001.$out_fmt z50c.until0:03.9001.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-# (encode) $desc... "
+       run_flac $eopt --until=-10 -o z50c.until-10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-10.$in_fmt z50c.until-10.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until-10.$in_fmt || die "ERROR: file mismatch for --until=-10 (encode) $desc"
+       rm -f z50c.until-10.$out_fmt z50c.until-10.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-mm:ss (encode) $desc... "
+       run_flac $eopt --until=-0:01 -o z50c.until-0:01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-0:01.$in_fmt z50c.until-0:01.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until-0:01.$in_fmt || die "ERROR: file mismatch for --until=-0:01 (encode) $desc"
+       rm -f z50c.until-0:01.$out_fmt z50c.until-0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-mm:ss.sss (encode) $desc... "
+       run_flac $eopt --until=-0:01.1001 -o z50c.until-0:01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.until-0:01.1001.$in_fmt z50c.until-0:01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until39.$in_fmt z50c.until-0:01.1001.$in_fmt || die "ERROR: file mismatch for --until=-0:01.1001 (encode) $desc"
+       rm -f z50c.until-0:01.1001.$out_fmt z50c.until-0:01.1001.$in_fmt
+       echo OK
+
+       #
+       # test --until when decoding
+       #
+
+       if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+       echo -n "testing --until=# (decode) $desc... "
+       run_flac $dopt --until=40 -o z50c.until40.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until40.$in_fmt || die "ERROR: file mismatch for --until=40 (decode) $desc"
+       rm -f z50c.until40.$in_fmt
+       echo OK
+
+       echo -n "testing --until=mm:ss (decode) $desc... "
+       run_flac $dopt --until=0:04 -o z50c.until0:04.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until0:04.$in_fmt || die "ERROR: file mismatch for --until=0:04 (decode) $desc"
+       rm -f z50c.until0:04.$in_fmt
+       echo OK
+
+       echo -n "testing --until=mm:ss.sss (decode) $desc... "
+       run_flac $dopt --until=0:03.9001 -o z50c.until0:03.9001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until39.$in_fmt z50c.until0:03.9001.$in_fmt || die "ERROR: file mismatch for --until=0:03.9001 (decode) $desc"
+       rm -f z50c.until0:03.9001.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-# (decode) $desc... "
+       run_flac $dopt --until=-10 -o z50c.until-10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until-10.$in_fmt || die "ERROR: file mismatch for --until=-10 (decode) $desc"
+       rm -f z50c.until-10.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-mm:ss (decode) $desc... "
+       run_flac $dopt --until=-0:01 -o z50c.until-0:01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.until-0:01.$in_fmt || die "ERROR: file mismatch for --until=-0:01 (decode) $desc"
+       rm -f z50c.until-0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --until=-mm:ss.sss (decode) $desc... "
+       run_flac $dopt --until=-0:01.1001 -o z50c.until-0:01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until39.$in_fmt z50c.until-0:01.1001.$in_fmt || die "ERROR: file mismatch for --until=-0:01.1001 (decode) $desc"
+       rm -f z50c.until-0:01.1001.$in_fmt
+       echo OK
+
+       rm -f z50c.$out_fmt
+
+       #
+       # test --skip and --until when encoding
+       #
+
+       echo -n "testing --skip=10 --until=# (encode) $desc... "
+       run_flac $eopt --skip=10 --until=40 -o z50c.skip10.until40.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until40.$in_fmt z50c.skip10.until40.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until40.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=40 (encode) $desc"
+       rm -f z50c.skip10.until40.$out_fmt z50c.skip10.until40.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=mm:ss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=0:04 -o z50c.skip10.until0:04.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until0:04.$in_fmt z50c.skip10.until0:04.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until0:04.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:04 (encode) $desc"
+       rm -f z50c.skip10.until0:04.$out_fmt z50c.skip10.until0:04.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=mm:ss.sss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=0:03.9001 -o z50c.skip10.until0:03.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until0:03.9001.$in_fmt z50c.skip10.until0:03.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until39.$in_fmt z50c.skip10.until0:03.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:03.9001 (encode) $desc"
+       rm -f z50c.skip10.until0:03.9001.$out_fmt z50c.skip10.until0:03.9001.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=+# (encode) $desc... "
+       run_flac $eopt --skip=10 --until=+30 -o z50c.skip10.until+30.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+30.$in_fmt z50c.skip10.until+30.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until+30.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+30 (encode) $desc"
+       rm -f z50c.skip10.until+30.$out_fmt z50c.skip10.until+30.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=+mm:ss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=+0:03 -o z50c.skip10.until+0:03.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+0:03.$in_fmt z50c.skip10.until+0:03.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until+0:03.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+0:03 (encode) $desc"
+       rm -f z50c.skip10.until+0:03.$out_fmt z50c.skip10.until+0:03.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=+mm:ss.sss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=+0:02.9001 -o z50c.skip10.until+0:02.9001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until+0:02.9001.$in_fmt z50c.skip10.until+0:02.9001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until39.$in_fmt z50c.skip10.until+0:02.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=+0:02.9001 (encode) $desc"
+       rm -f z50c.skip10.until+0:02.9001.$out_fmt z50c.skip10.until+0:02.9001.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-# (encode) $desc... "
+       run_flac $eopt --skip=10 --until=-10 -o z50c.skip10.until-10.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-10.$in_fmt z50c.skip10.until-10.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-10.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-10 (encode) $desc"
+       rm -f z50c.skip10.until-10.$out_fmt z50c.skip10.until-10.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-mm:ss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=-0:01 -o z50c.skip10.until-0:01.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-0:01.$in_fmt z50c.skip10.until-0:01.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-0:01.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01 (encode) $desc"
+       rm -f z50c.skip10.until-0:01.$out_fmt z50c.skip10.until-0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-mm:ss.sss (encode) $desc... "
+       run_flac $eopt --skip=10 --until=-0:01.1001 -o z50c.skip10.until-0:01.1001.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+       [ $in_fmt = $out_fmt ] || run_flac $dopt -o z50c.skip10.until-0:01.1001.$in_fmt z50c.skip10.until-0:01.1001.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until39.$in_fmt z50c.skip10.until-0:01.1001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01.1001 (encode) $desc"
+       rm -f z50c.skip10.until-0:01.1001.$out_fmt z50c.skip10.until-0:01.1001.$in_fmt
+       echo OK
+
+       #
+       # test --skip and --until when decoding
+       #
+
+       if [ $in_fmt != $out_fmt ] ; then run_flac $eopt -o z50c.$out_fmt 50c.$in_fmt ; else cp -f 50c.$in_fmt z50c.$out_fmt ; fi || die "ERROR generating FLAC file $desc"
+
+
+       echo -n "testing --skip=10 --until=# (decode) $desc... "
+       run_flac $dopt --skip=10 --until=40 -o z50c.skip10.until40.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until40.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=40 (decode) $desc"
+       rm -f z50c.skip10.until40.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=mm:ss (decode) $desc... "
+       run_flac $dopt --skip=10 --until=0:04 -o z50c.skip10.until0:04.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until0:04.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:04 (decode) $desc"
+       rm -f z50c.skip10.until0:04.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=mm:ss.sss (decode) $desc... "
+       run_flac $dopt --skip=10 --until=0:03.9001 -o z50c.skip10.until0:03.9001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until39.$in_fmt z50c.skip10.until0:03.9001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=0:03.9001 (decode) $desc"
+       rm -f z50c.skip10.until0:03.9001.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-# (decode) $desc... "
+       run_flac $dopt --skip=10 --until=-10 -o z50c.skip10.until-10.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-10.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-10 (decode) $desc"
+       rm -f z50c.skip10.until-10.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-mm:ss (decode) $desc... "
+       run_flac $dopt --skip=10 --until=-0:01 -o z50c.skip10.until-0:01.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.skip10.until-0:01.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01 (decode) $desc"
+       rm -f z50c.skip10.until-0:01.$in_fmt
+       echo OK
+
+       echo -n "testing --skip=10 --until=-mm:ss.sss (decode) $desc... "
+       run_flac $dopt --skip=10 --until=-0:01.1001 -o z50c.skip10.until-0:01.1001.$in_fmt z50c.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until39.$in_fmt z50c.skip10.until-0:01.1001.$in_fmt || die "ERROR: file mismatch for --skip=10 --until=-0:01.1001 (decode) $desc"
+       rm -f z50c.skip10.until-0:01.1001.$in_fmt
+       echo OK
+
+       rm -f z50c.$out_fmt
+}
+
+test_skip_until raw flac
+test_skip_until wav flac
+test_skip_until aiff flac
+test_skip_until flac flac
+#@@@if [ $has_ogg = yes ] ; then
+#@@@   #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@   test_skip_until ogg flac
+#@@@fi
+
+if [ $has_ogg = yes ] ; then
+       test_skip_until raw ogg
+       test_skip_until wav ogg
+       test_skip_until aiff ogg
+       #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+       #@@@test_skip_until flac ogg
+       #@@@test_skip_until ogg ogg
+fi
+
+echo "testing seek extremes:"
+
+run_flac --verify --force $SILENT --no-padding --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 noise.raw || die "ERROR generating FLAC file"
+
+if [ $is_win = no ] ; then
+       total_noise_cdda_samples=`run_metaflac --show-total-samples noise.flac`
+       [ $? = 0 ] || die "ERROR getting total sample count from noise.flac"
+else
+       # some flavors of cygwin don't seem to treat the \x0d as a word
+       # separator, so we hard code it.  we'll just have to fix it later
+       # if we change the way noise.flac is made.
+       total_noise_cdda_samples=393216
+fi
+
+echo -n "testing --skip=0... "
+run_flac $wav_dopt --skip=0 -o z.wav noise.flac || die "ERROR decoding FLAC file noise.flac"
+echo OK
+
+for delta in 2 1 ; do
+       n=`expr $total_noise_cdda_samples - $delta`
+       echo -n "testing --skip=$n... "
+       run_flac $wav_dopt --skip=$n -o z.wav noise.flac || die "ERROR decoding FLAC file noise.flac"
+       echo OK
+done
+
+rm noise.flac z.wav
+
+
+############################################################################
+# test --input-size
+############################################################################
+
+#@@@ cat will not work on old cygwin, need to fix
+if [ $is_win = no ] ; then
+       echo -n "testing --input-size=50 --skip=10... "
+       cat 50c.raw | run_flac $raw_eopt --input-size=50 --skip=10 -o z50c.skip10.flac - || die "ERROR generating FLAC file"
+       run_flac $raw_dopt -o z50c.skip10.raw z50c.skip10.flac || die "ERROR decoding FLAC file"
+       cmp 50c.skip10.raw z50c.skip10.raw || die "ERROR: file mismatch for --input-size=50 --skip=10"
+       rm -f z50c.skip10.raw z50c.skip10.flac
+       echo OK
+fi
+
+
+############################################################################
+# test --cue
+############################################################################
+
+#
+# create the cue sheet
+#
+cuesheet=cuetest.cue
+cat > $cuesheet << EOF
+CATALOG 1234567890123
+FILE "blah" WAVE
+  TRACK 01 AUDIO
+    INDEX 01 0
+    INDEX 02 10
+    INDEX 03 20
+  TRACK 02 AUDIO
+    INDEX 01 30
+  TRACK 04 AUDIO
+    INDEX 01 40
+EOF
+
+test_cue ()
+{
+       in_fmt=$1
+       out_fmt=$2
+
+       [ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
+
+       [ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
+
+       if [ $in_fmt = raw ] ; then
+               eopt="$raw_eopt"
+               dopt="$raw_dopt"
+       else
+               eopt="$wav_eopt"
+               dopt="$wav_dopt"
+       fi
+
+       if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
+               CMP=md5cmp
+       else
+               CMP=cmp
+       fi
+
+       if [ $out_fmt = ogg ] ; then
+               eopt="--ogg $eopt"
+       fi
+
+       desc="($in_fmt<->$out_fmt)"
+
+       #
+       # for this we need just need just one FLAC file; --cue only works while decoding
+       #
+       run_flac $eopt --cuesheet=$cuesheet -o z50c.cue.$out_fmt 50c.$in_fmt || die "ERROR generating FLAC file $desc"
+
+       # To make it easy to translate from cue point to sample numbers, the
+       # file has a sample rate of 10 Hz and a cuesheet like so:
+       #
+       # TRACK 01, INDEX 01 : 0:00.00 -> sample 0
+       # TRACK 01, INDEX 02 : 0:01.00 -> sample 10
+       # TRACK 01, INDEX 03 : 0:02.00 -> sample 20
+       # TRACK 02, INDEX 01 : 0:03.00 -> sample 30
+       # TRACK 04, INDEX 01 : 0:04.00 -> sample 40
+       #
+       echo -n "testing --cue=- $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=- $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.0 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.0- $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0- $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.1 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.1- $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1- $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.2 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.2- $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2- $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.4 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip20.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.4- $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4- z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip20.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4- $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=-5.0 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-5.0 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=-4.1 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=-4.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-4.1 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=-3.1 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=-3.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-3.1 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=-1.4 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=-1.4 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.until30.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=-1.4 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.0-5.0 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.0-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.0-5.0 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.1-5.0 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.1-5.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.1-5.0 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.2-4.1 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.2-4.1 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip10.until40.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.2-4.1 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       echo -n "testing --cue=1.4-2.0 $desc... "
+       run_flac $dopt -o z50c.cued.$in_fmt --cue=1.4-2.0 z50c.cue.$out_fmt || die "ERROR decoding FLAC file $desc"
+       $CMP 50c.skip20.until30.$in_fmt z50c.cued.$in_fmt || die "ERROR: file mismatch for --cue=1.4-2.0 $desc"
+       rm -f z50c.cued.$in_fmt
+       echo OK
+
+       rm -f z50c.cue.$out_fmt
+}
+
+test_cue raw flac
+test_cue wav flac
+test_cue aiff flac
+test_cue flac flac
+#@@@if [ $has_ogg = yes ] ; then
+#@@@   #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@   test_cue ogg flac
+#@@@fi
+
+if [ $has_ogg = yes ] ; then
+       test_cue raw ogg
+       test_cue wav ogg
+       test_cue aiff ogg
+       #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+       #@@@test_cue flac ogg
+       #@@@test_cue ogg ogg
+fi
+
+############################################################################
+# test 'fixup' code that happens when a FLAC file with total_samples == 0
+# in the STREAMINFO block is converted to WAVE or AIFF, requiring the
+# decoder go back and fix up the chunk headers
+############################################################################
+
+echo -n "WAVE fixup test... "
+
+echo -n "prepare... "
+convert_to_wav noise "$raw_eopt" "$wav_dopt" || die "ERROR creating reference WAVE"
+
+echo -n "encode... "
+# the pipe from 'cat' to 'flac' does not work on cygwin because of the EOF/
+# binary-mode stdin problem, so we use an undocumented option to metaflac to
+# set the total sample count to 0
+if [ $is_win = yes ] ; then
+       run_flac $raw_eopt noise.raw -o fixup.flac || die "ERROR generating FLAC file"
+       run_metaflac --set-total-samples=0 fixup.flac 2> /dev/null
+else
+       cat noise.raw | run_flac $raw_eopt - -c > fixup.flac || die "ERROR generating FLAC file"
+fi
+
+echo -n "decode... "
+run_flac $wav_dopt fixup.flac -o fixup.wav || die "ERROR decoding FLAC file"
+
+echo -n "compare... "
+cmp noise.wav fixup.wav || die "ERROR: file mismatch"
+
+echo OK
+rm -f noise.wav fixup.wav fixup.flac
+
+echo -n "AIFF fixup test... "
+
+echo -n "prepare... "
+convert_to_aiff noise "$raw_eopt" "$wav_dopt" || die "ERROR creating reference AIFF"
+
+echo -n "encode... "
+# the pipe from 'cat' to 'flac' does not work on cygwin because of the EOF/
+# binary-mode stdin problem, so we use an undocumented option to metaflac to
+# set the total sample count to 0
+if [ $is_win = yes ] ; then
+       run_flac $raw_eopt noise.raw -o fixup.flac || die "ERROR generating FLAC file"
+       run_metaflac --set-total-samples=0 fixup.flac 2> /dev/null
+else
+       cat noise.raw | run_flac $raw_eopt - -c > fixup.flac || die "ERROR generating FLAC file"
+fi
+
+echo -n "decode... "
+run_flac $wav_dopt fixup.flac -o fixup.aiff || die "ERROR decoding FLAC file"
+
+echo -n "compare... "
+cmp noise.aiff fixup.aiff || die "ERROR: file mismatch"
+
+echo OK
+rm -f noise.aiff fixup.aiff fixup.flac
+
+
+############################################################################
+# multi-file tests
+############################################################################
+
+echo "Generating multiple input files from noise..."
+multifile_format_decode="--endian=big --sign=signed"
+multifile_format_encode="$multifile_format_decode --sample-rate=44100 --bps=16 --channels=2 --no-padding"
+short_noise_cdda_samples=`expr $total_noise_cdda_samples / 8`
+run_flac --verify --force $SILENT --force-raw-format $multifile_format_encode --until=$short_noise_cdda_samples -o shortnoise.flac noise.raw || die "ERROR generating FLAC file"
+run_flac --decode --force $SILENT shortnoise.flac -o shortnoise.raw --force-raw-format $multifile_format_decode || die "ERROR generating RAW file"
+run_flac --decode --force $SILENT shortnoise.flac || die "ERROR generating WAVE file"
+run_flac --decode --force $SILENT shortnoise.flac -o shortnoise.aiff || die "ERROR generating AIFF file"
+cp shortnoise.flac file0.flac
+cp shortnoise.flac file1.flac
+cp shortnoise.flac file2.flac
+rm -f shortnoise.flac
+cp shortnoise.wav file0.wav
+cp shortnoise.wav file1.wav
+cp shortnoise.wav file2.wav
+rm -f shortnoise.wav
+cp shortnoise.aiff file0.aiff
+cp shortnoise.aiff file1.aiff
+cp shortnoise.aiff file2.aiff
+rm -f shortnoise.aiff
+cp shortnoise.raw file0.raw
+cp shortnoise.raw file1.raw
+cp shortnoise.raw file2.raw
+rm -f shortnoise.raw
+# create authoritative sector-aligned files for comparison
+file0_samples=`expr \( $short_noise_cdda_samples / 588 \) \* 588`
+file0_remainder=`expr $short_noise_cdda_samples - $file0_samples`
+file1_samples=`expr \( \( $file0_remainder + $short_noise_cdda_samples \) / 588 \) \* 588`
+file1_remainder=`expr $file0_remainder + $short_noise_cdda_samples - $file1_samples`
+file1_samples=`expr $file1_samples - $file0_remainder`
+file2_samples=`expr \( \( $file1_remainder + $short_noise_cdda_samples \) / 588 \) \* 588`
+file2_remainder=`expr $file1_remainder + $short_noise_cdda_samples - $file2_samples`
+file2_samples=`expr $file2_samples - $file1_remainder`
+if [ $file2_remainder != '0' ] ; then
+       file2_samples=`expr $file2_samples + $file2_remainder`
+       file2_remainder=`expr 588 - $file2_remainder`
+fi
+
+dd if=file0.raw ibs=4 count=$file0_samples of=file0s.raw 2>/dev/null || $dddie
+dd if=file0.raw ibs=4 count=$file0_remainder of=file1s.raw skip=$file0_samples 2>/dev/null || $dddie
+dd if=file1.raw ibs=4 count=$file1_samples of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file1s.raw || die "ERROR: cat-ing sector-aligned files"
+dd if=file1.raw ibs=4 count=$file1_remainder of=file2s.raw skip=$file1_samples 2>/dev/null || $dddie
+dd if=file2.raw ibs=4 count=$file2_samples of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file2s.raw || die "ERROR: cat-ing sector-aligned files"
+dd if=/dev/zero ibs=4 count=$file2_remainder of=z.raw 2>/dev/null || $dddie
+cat z.raw >> file2s.raw || die "ERROR: cat-ing sector-aligned files"
+rm -f z.raw
+
+convert_to_wav file0s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+convert_to_wav file1s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+convert_to_wav file2s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned WAVE"
+
+convert_to_aiff file0s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+convert_to_aiff file1s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+convert_to_aiff file2s "$multifile_format_encode --force" "$SILENT --force --decode" || die "ERROR creating authoritative sector-aligned AIFF"
+
+test_multifile ()
+{
+       input_type=$1
+       streamtype=$2
+       sector_align=$3
+       encode_options="$4"
+
+       extra_encode_options=""
+       extra_decode_options=""
+       if [ $input_type = "raw" ] ; then
+               extra_encode_options="--force-raw-format $multifile_format_encode"
+               extra_decode_options="--force-raw-format $multifile_format_decode"
+       else
+               if [ $input_type = "aiff" ] ; then
+                       extra_decode_options="--force-aiff-format"
+               fi
+       fi
+
+       if [ $streamtype = ogg ] ; then
+               suffix=oga
+               encode_options="$encode_options --ogg"
+       else
+               suffix=flac
+       fi
+
+       if [ $sector_align = sector_align ] ; then
+               encode_options="$encode_options --sector-align"
+       fi
+
+       if [ $input_type = flac ] || [ $input_type = ogg ] ; then
+               CMP=md5cmp
+       else
+               CMP=cmp
+       fi
+
+       for n in 0 1 2 ; do
+               cp file$n.$input_type file${n}x.$input_type
+       done
+       run_flac --force $encode_options $extra_encode_options file0x.$input_type file1x.$input_type file2x.$input_type || die "ERROR"
+       run_flac --force --decode $extra_decode_options file0x.$suffix file1x.$suffix file2x.$suffix || die "ERROR"
+       if [ $sector_align != sector_align ] ; then
+               for n in 0 1 2 ; do
+                       $CMP file$n.$input_type file${n}x.$input_type || die "ERROR: file mismatch on file #$n"
+               done
+       else
+               for n in 0 1 2 ; do
+                       $CMP file${n}s.$input_type file${n}x.$input_type || die "ERROR: file mismatch on file #$n"
+               done
+       fi
+       for n in 0 1 2 ; do
+               rm -f file${n}x.$suffix file${n}x.$input_type
+       done
+}
+
+input_types="raw wav aiff flac"
+#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
+#@@@if [ $has_ogg = yes ] ; then
+#@@@   input_types="$input_types ogg"
+#@@@fi
+for input_type in $input_types ; do
+       echo "Testing multiple $input_type files without verify..."
+       test_multifile $input_type flac no_sector_align ""
+
+       echo "Testing multiple $input_type files with verify..."
+       test_multifile $input_type flac no_sector_align "--verify"
+
+       if [ $input_type != flac ] && [ $input_type != ogg ] ; then # --sector-align not supported for FLAC input
+               echo "Testing multiple $input_type files with --sector-align, without verify..."
+               test_multifile $input_type flac sector_align ""
+
+               echo "Testing multiple $input_type files with --sector-align, with verify..."
+               test_multifile $input_type flac sector_align "--verify"
+       fi
+
+       if [ $has_ogg = yes ] ; then
+               echo "Testing multiple $input_type files with --ogg, without verify..."
+               test_multifile $input_type ogg no_sector_align ""
+
+               echo "Testing multiple $input_type files with --ogg, with verify..."
+               test_multifile $input_type ogg no_sector_align "--verify"
+
+               if [ $input_type != flac ] ; then # --sector-align not supported for FLAC input
+                       echo "Testing multiple $input_type files with --ogg and --sector-align, without verify..."
+                       test_multifile $input_type ogg sector_align ""
+
+                       echo "Testing multiple $input_type files with --ogg and --sector-align, with verify..."
+                       test_multifile $input_type ogg sector_align "--verify"
+               fi
+
+               echo "Testing multiple $input_type files with --ogg and --serial-number, with verify..."
+               test_multifile $input_type ogg no_sector_align "--serial-number=321 --verify"
+       fi
+done
+
+
+############################################################################
+# test the metadata-handling properties of flac-to-flac encoding
+############################################################################
+
+echo "Testing the metadata-handling properties of flac-to-flac encoding..."
+
+testdir="flac-to-flac-metadata-test-files"
+filter ()
+{
+       # minor danger, changing vendor strings might change the length of the
+       # VORBIS_COMMENT block, but if we add "^  length: " to the patterns,
+       # we lose info about PADDING size that we need
+       grep -Ev '^  vendor string: |^  m..imum .....size: ' | sed -e 's/, stream_offset.*//'
+}
+flac2flac ()
+{
+       file="$1"
+       case="$2"
+       args="$3"
+       expect="$case-expect.meta"
+       echo -n "$case... "
+       run_flac $SILENT -f -o out.flac $args $file || die "ERROR encoding FLAC file"
+       run_metaflac --list out.flac | filter > out.meta || die "ERROR listing metadata of output FLAC file"
+       diff -q -w $expect out.meta 2>/dev/null || die "ERROR: metadata does not match expected $expect"
+       echo OK
+}
+
+#filter=', stream_offset.*|^  vendor string: |^  length: |^  m..imum .....size: '
+cd $testdir || die "ERROR changing to directory $testdir"
+
+# case 00a: no alterations on a file with all metadata types, keep all metadata, in same order
+flac2flac input-SCVAUP.flac case00a ""
+# case 01a: on file with multiple PADDING blocks, they should be aggregated into one at the end
+flac2flac input-SCVPAP.flac case01a ""
+# case 01b: on file with multiple PADDING blocks and --no-padding specified, they should all be deleted
+flac2flac input-SCVPAP.flac case01b "--no-padding"
+# case 01c: on file with multiple PADDING blocks and -P specified, they should all be overwritten with -P value
+flac2flac input-SCVPAP.flac case01c "-P 1234"
+# case 01d: on file with no PADDING blocks, use -P setting
+flac2flac input-SCVA.flac case01d "-P 1234"
+# case 01e: on file with no PADDING blocks and no -P given, use default padding
+flac2flac input-SCVA.flac case01e ""
+# case 02a: on file with no VORBIS_COMMENT block, add new VORBIS_COMMENT
+flac2flac input-SCPAP.flac case02a ""
+# case 02b: on file with no VORBIS_COMMENT block and --tag, add new VORBIS_COMMENT with tags
+flac2flac input-SCPAP.flac case02b "--tag=artist=0"
+# case 02c: on file with VORBIS_COMMENT block and --tag, replace existing VORBIS_COMMENT with new tags
+flac2flac input-SCVAUP.flac case02c "$TOTALLY_SILENT --tag=artist=0"
+# case 03a: on file with no CUESHEET block and --cuesheet specified, add it
+flac2flac input-SVAUP.flac case03a "--cuesheet=input0.cue"
+# case 03b: on file with CUESHEET block and --cuesheet specified, overwrite existing CUESHEET
+flac2flac input-SCVAUP.flac case03b "$TOTALLY_SILENT --cuesheet=input0.cue"
+# case 03c: on file with CUESHEET block and size-changing option specified, drop existing CUESHEET
+flac2flac input-SCVAUP.flac case03c "$TOTALLY_SILENT --skip=1"
+# case 04a: on file with no SEEKTABLE block and --no-seektable specified, no SEEKTABLE
+flac2flac input-VA.flac case04a "--no-padding --no-seektable"
+# case 04b: on file with no SEEKTABLE block and -S specified, new SEEKTABLE
+flac2flac input-VA.flac case04b "--no-padding -S 5x"
+# case 04c: on file with no SEEKTABLE block and no seektable options specified, new SEEKTABLE with default points
+flac2flac input-VA.flac case04c "--no-padding"
+# case 04d: on file with SEEKTABLE block and --no-seektable specified, drop existing SEEKTABLE
+flac2flac input-SCVA.flac case04d "--no-padding --no-seektable"
+# case 04e: on file with SEEKTABLE block and -S specified, overwrite existing SEEKTABLE
+flac2flac input-SCVA.flac case04e "$TOTALLY_SILENT --no-padding -S 5x"
+# case 04f: on file with SEEKTABLE block and size-changing option specified, drop existing SEEKTABLE, new SEEKTABLE with default points
+#(already covered by case03c)
+
+rm -f out.flac out.meta
+
+#@@@ when metaflac handles ogg flac, duplicate flac2flac tests here
+
+cd ..
diff --git a/test/test_grabbag.sh b/test/test_grabbag.sh
new file mode 100755 (executable)
index 0000000..a18a931
--- /dev/null
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/test_grabbag/cuesheet:$PATH
+PATH=../src/test_grabbag/picture:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+test_cuesheet -h 1>/dev/null 2>/dev/null || die "ERROR can't find test_cuesheet executable"
+test_picture -h 1>/dev/null 2>/dev/null || die "ERROR can't find test_picture executable"
+
+run_test_cuesheet ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 test_cuesheet $*" >>test_grabbag.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 test_cuesheet $* 4>>test_grabbag.valgrind.log
+       else
+               test_cuesheet $*
+       fi
+}
+
+run_test_picture ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 test_picture $*" >>test_grabbag.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 test_picture $* 4>>test_grabbag.valgrind.log
+       else
+               test_picture $*
+       fi
+}
+
+if [ `env | grep -ic '^comspec='` != 0 ] ; then
+       is_win=yes
+else
+       is_win=no
+fi
+
+########################################################################
+#
+# test_picture
+#
+########################################################################
+
+log=picture.log
+picture_dir=pictures
+
+echo "Running test_picture..."
+
+rm -f $log
+
+run_test_picture $picture_dir >> $log 2>&1
+
+if [ $is_win = yes ] ; then
+       diff -w picture.ok $log > picture.diff || die "Error: .log file does not match .ok file, see picture.diff"
+else
+       diff picture.ok $log > picture.diff || die "Error: .log file does not match .ok file, see picture.diff"
+fi
+
+echo "PASSED (results are in $log)"
+
+########################################################################
+#
+# test_cuesheet
+#
+########################################################################
+
+log=cuesheet.log
+bad_cuesheets=cuesheets/bad.*.cue
+good_cuesheets=cuesheets/good.*.cue
+good_leadout=`expr 80 \* 60 \* 44100`
+bad_leadout=`expr $good_leadout + 1`
+
+echo "Running test_cuesheet..."
+
+rm -f $log
+
+#
+# negative tests
+#
+for cuesheet in $bad_cuesheets ; do
+       echo "NEGATIVE $cuesheet" >> $log 2>&1
+       run_test_cuesheet $cuesheet $good_leadout cdda >> $log 2>&1
+       exit_code=$?
+       if [ "$exit_code" = 255 ] ; then
+               die "Error: test script is broken"
+       fi
+       cuesheet_pass1=${cuesheet}.1
+       cuesheet_pass2=${cuesheet}.2
+       rm -f $cuesheet_pass1 $cuesheet_pass2
+done
+
+#
+# positve tests
+#
+for cuesheet in $good_cuesheets ; do
+       echo "POSITIVE $cuesheet" >> $log 2>&1
+       run_test_cuesheet $cuesheet $good_leadout cdda >> $log 2>&1
+       exit_code=$?
+       if [ "$exit_code" = 255 ] ; then
+               die "Error: test script is broken"
+       elif [ "$exit_code" != 0 ] ; then
+               die "Error: good cuesheet is broken"
+       fi
+       cuesheet_pass1=${cuesheet}.1
+       cuesheet_pass2=${cuesheet}.2
+       diff $cuesheet_pass1 $cuesheet_pass2 >> $log 2>&1 || die "Error: pass1 and pass2 output differ"
+       rm -f $cuesheet_pass1 $cuesheet_pass2
+done
+
+if [ $is_win = yes ] ; then
+       diff -w cuesheet.ok $log > cuesheet.diff || die "Error: .log file does not match .ok file, see cuesheet.diff"
+else
+       diff cuesheet.ok $log > cuesheet.diff || die "Error: .log file does not match .ok file, see cuesheet.diff"
+fi
+
+echo "PASSED (results are in $log)"
diff --git a/test/test_libFLAC++.sh b/test/test_libFLAC++.sh
new file mode 100755 (executable)
index 0000000..550c6bd
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/libFLAC++/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/test_libFLAC++:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+run_test_libFLACpp ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 test_libFLAC++ $* 4>>test_libFLAC++.valgrind.log
+       else
+               test_libFLAC++ $*
+       fi
+}
+
+run_test_libFLACpp || die "ERROR during test_libFLAC++"
diff --git a/test/test_libFLAC.sh b/test/test_libFLAC.sh
new file mode 100755 (executable)
index 0000000..5343ef0
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/test_libFLAC:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+run_test_libFLAC ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 test_libFLAC $* 4>>test_libFLAC.valgrind.log
+       else
+               test_libFLAC $*
+       fi
+}
+
+run_test_libFLAC || die "ERROR during test_libFLAC"
diff --git a/test/test_metaflac.sh b/test/test_metaflac.sh
new file mode 100755 (executable)
index 0000000..f7cdedf
--- /dev/null
@@ -0,0 +1,397 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+# change to 'false' to show all flac/metaflac output (useful for debugging)
+if true ; then
+       SILENT='--silent'
+       TOTALLY_SILENT='--totally-silent'
+else
+       SILENT=''
+       TOTALLY_SILENT=''
+fi
+
+LD_LIBRARY_PATH=`pwd`/../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../src/share/utf8/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=`pwd`/../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=`pwd`/../src/flac:$PATH
+PATH=`pwd`/../src/metaflac:$PATH
+PATH=`pwd`/../obj/$BUILD/bin:$PATH
+
+if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+       then EGREP='grep -E'
+       else EGREP='egrep'
+fi
+
+testdir="metaflac-test-files"
+flacfile="metaflac.flac"
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+metaflac --help 1>/dev/null 2>/dev/null || die "ERROR can't find metaflac executable"
+
+run_flac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_metaflac.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 flac $* 4>>test_metaflac.valgrind.log
+       else
+               flac $*
+       fi
+}
+
+run_metaflac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 metaflac $*" >>test_metaflac.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 metaflac $* 4>>test_metaflac.valgrind.log
+       else
+               metaflac $*
+       fi
+}
+
+run_metaflac_silent ()
+{
+       if [ -z "$SILENT" ] ; then
+               run_metaflac $*
+       else
+               if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+                       echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 metaflac $*" >>test_metaflac.valgrind.log
+                       valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 metaflac $* 2>/dev/null 4>>test_metaflac.valgrind.log
+               else
+                       metaflac $* 2>/dev/null
+               fi
+       fi
+}
+
+check_flac ()
+{
+       run_flac --silent --test $flacfile || die "ERROR in $flacfile" 1>&2
+}
+
+echo "Generating stream..."
+bytes=80000
+if dd if=/dev/zero ibs=1 count=$bytes | flac --force --verify -0 --input-size=$bytes --output-name=$flacfile --force-raw-format --endian=big --sign=signed --channels=1 --bps=8 --sample-rate=8000 - ; then
+       chmod +w $flacfile
+else
+       die "ERROR during generation"
+fi
+
+check_flac
+
+echo
+
+filter ()
+{
+       # minor danger, changing vendor strings will change the length of the
+       # VORBIS_COMMENT block, but if we add "^  length: " to the patterns,
+       # we lose info about PADDING size that we need
+       # grep pattern 1: remove vendor string
+       # grep pattern 2: remove minimum/maximum frame and block size from STREAMINFO
+       # grep pattern 3: remove hexdump data from PICTURE metadata blocks
+       # sed pattern 1: remove stream offset values from SEEKTABLE points
+       $EGREP -v '^  vendor string: |^  m..imum .....size: |^    0000[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]: ' | sed -e 's/, stream_offset.*//'
+}
+metaflac_test ()
+{
+       case="$1"
+       desc="$2"
+       args="$3"
+       expect="$testdir/$case-expect.meta"
+       echo -n "test $case: $desc... "
+       run_metaflac $args $flacfile | filter > $testdir/out.meta || die "ERROR running metaflac"
+       diff -w $expect $testdir/out.meta > /dev/null 2>&1 || die "ERROR: metadata does not match expected $expect"
+       echo OK
+}
+
+metaflac_test case00 "--list" "--list"
+
+metaflac_test case01 "STREAMINFO --show-* shortcuts" "
+       --show-md5sum
+       --show-min-blocksize
+       --show-max-blocksize
+       --show-min-framesize
+       --show-max-framesize
+       --show-sample-rate
+       --show-channels
+       --show-bps
+       --show-total-samples"
+
+run_metaflac --preserve-modtime --add-padding=12345 $flacfile
+check_flac
+metaflac_test case02 "--add-padding" "--list"
+
+# some flavors of /bin/sh (e.g. Darwin's) won't even handle quoted spaces, so we underscore:
+run_metaflac --set-tag="ARTIST=The_artist_formerly_known_as_the_artist..." $flacfile
+check_flac
+metaflac_test case03 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="ARTIST=Chuck_Woolery" $flacfile
+check_flac
+metaflac_test case04 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="ARTIST=Vern" $flacfile
+check_flac
+metaflac_test case05 "--set-tag=ARTIST" "--list"
+
+run_metaflac --set-tag="TITLE=He_who_smelt_it_dealt_it" $flacfile
+check_flac
+metaflac_test case06 "--set-tag=TITLE" "--list"
+
+metaflac_test case07 "--show-vendor-tag --show-tag=ARTIST" "--show-vendor-tag --show-tag=ARTIST"
+
+run_metaflac --remove-first-tag=ARTIST $flacfile
+check_flac
+metaflac_test case08 "--remove-first-tag=ARTIST" "--list"
+
+run_metaflac --remove-tag=ARTIST $flacfile
+check_flac
+metaflac_test case09 "--remove-tag=ARTIST" "--list"
+
+metaflac_test case10 "--list --block-type=VORBIS_COMMENT" "--list --block-type=VORBIS_COMMENT"
+metaflac_test case11 "--list --block-number=0" "--list --block-number=0"
+metaflac_test case12 "--list --block-number=1,2,999" "--list --block-number=1,2,999"
+metaflac_test case13 "--list --block-type=VORBIS_COMMENT,PADDING" "--list --block-type=VORBIS_COMMENT,PADDING"
+metaflac_test case14 "--list --except-block-type=SEEKTABLE,VORBIS_COMMENT" "--list --except-block-type=SEEKTABLE,VORBIS_COMMENT"
+metaflac_test case15 "--list --except-block-type=STREAMINFO" "--list --except-block-type=STREAMINFO"
+
+run_metaflac --add-padding=4321 $flacfile $flacfile
+check_flac
+metaflac_test case16 "--add-padding=4321 * 2" "--list"
+
+run_metaflac --merge-padding $flacfile
+check_flac
+metaflac_test case17 "--merge-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile
+check_flac
+metaflac_test case18 "--add-padding=0" "--list"
+
+run_metaflac --sort-padding $flacfile
+check_flac
+metaflac_test case19 "--sort-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile
+check_flac
+metaflac_test case20 "--add-padding=0" "--list"
+
+run_metaflac --remove-all-tags $flacfile
+check_flac
+metaflac_test case21 "--remove-all-tags" "--list"
+
+run_metaflac --remove --block-number=1,99 --dont-use-padding $flacfile
+check_flac
+metaflac_test case22 "--remove --block-number=1,99 --dont-use-padding" "--list"
+
+run_metaflac --remove --block-number=99 --dont-use-padding $flacfile
+check_flac
+metaflac_test case23 "--remove --block-number=99 --dont-use-padding" "--list"
+
+run_metaflac --remove --block-type=PADDING $flacfile
+check_flac
+metaflac_test case24 "--remove --block-type=PADDING" "--list"
+
+run_metaflac --remove --block-type=PADDING --dont-use-padding $flacfile
+check_flac
+metaflac_test case25 "--remove --block-type=PADDING --dont-use-padding" "--list"
+
+run_metaflac --add-padding=0 $flacfile $flacfile
+check_flac
+metaflac_test case26 "--add-padding=0 * 2" "--list"
+
+run_metaflac --remove --except-block-type=PADDING $flacfile
+check_flac
+metaflac_test case27 "--remove --except-block-type=PADDING" "--list"
+
+run_metaflac --remove-all $flacfile
+check_flac
+metaflac_test case28 "--remove-all" "--list"
+
+run_metaflac --remove-all --dont-use-padding $flacfile
+check_flac
+metaflac_test case29 "--remove-all --dont-use-padding" "--list"
+
+run_metaflac --remove-all --dont-use-padding $flacfile
+check_flac
+metaflac_test case30 "--remove-all --dont-use-padding" "--list"
+
+run_metaflac --set-tag="f=0123456789abcdefghij" $flacfile
+check_flac
+metaflac_test case31 "--set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghi" $flacfile
+check_flac
+metaflac_test case32 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcde" $flacfile
+check_flac
+metaflac_test case33 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0" $flacfile
+check_flac
+metaflac_test case34 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789" $flacfile
+check_flac
+metaflac_test case35 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghi" $flacfile
+check_flac
+metaflac_test case36 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789" $flacfile
+check_flac
+metaflac_test case37 "--remove-all-tags --set-tag=..." "--list"
+
+run_metaflac --remove-all-tags --set-tag="f=0123456789abcdefghij" $flacfile
+check_flac
+metaflac_test case38 "--remove-all-tags --set-tag=..." "--list"
+
+echo "TITLE=Tittle" | run_metaflac --import-tags-from=- $flacfile
+check_flac
+metaflac_test case39 "--import-tags-from=-" "--list"
+
+cat > vc.txt << EOF
+artist=Fartist
+artist=artits
+EOF
+run_metaflac --import-tags-from=vc.txt $flacfile
+check_flac
+metaflac_test case40 "--import-tags-from=[FILE]" "--list"
+
+rm vc.txt
+
+run_metaflac --add-replay-gain $flacfile
+check_flac
+metaflac_test case41 "--add-replay-gain" "--list"
+
+run_metaflac --remove-replay-gain $flacfile
+check_flac
+metaflac_test case42 "--remove-replay-gain" "--list"
+
+# CUESHEET blocks
+cs_in=cuesheets/good.000.cue
+cs_out=metaflac.cue
+cs_out2=metaflac2.cue
+run_metaflac --import-cuesheet-from="$cs_in" $flacfile
+check_flac
+metaflac_test case43 "--import-cuesheet-from" "--list"
+run_metaflac --export-cuesheet-to=$cs_out $flacfile
+run_metaflac --remove --block-type=CUESHEET $flacfile
+check_flac
+metaflac_test case44 "--remove --block-type=CUESHEET" "--list"
+run_metaflac --import-cuesheet-from=$cs_out $flacfile
+check_flac
+metaflac_test case45 "--import-cuesheet-from" "--list"
+run_metaflac --export-cuesheet-to=$cs_out2 $flacfile
+echo "comparing cuesheets:"
+diff $cs_out $cs_out2 || die "ERROR, cuesheets should be identical"
+echo identical
+
+rm -f $cs_out $cs_out2
+
+# PICTURE blocks
+ncase=46
+for f in \
+       0.gif \
+       1.gif \
+       2.gif \
+; do
+       run_metaflac --import-picture-from="|image/gif|$f||pictures/$f" $flacfile
+       check_flac
+       metaflac_test "case$ncase" "--import-picture-from" "--list"
+       ncase=`expr $ncase + 1`
+done
+for f in \
+       0.jpg \
+       4.jpg \
+; do
+       run_metaflac --import-picture-from="4|image/jpeg|$f||pictures/$f" $flacfile
+       check_flac
+       metaflac_test "case$ncase" "--import-picture-from" "--list"
+       ncase=`expr $ncase + 1`
+done
+for f in \
+       0.png \
+       1.png \
+       2.png \
+       3.png \
+       4.png \
+       5.png \
+       6.png \
+       7.png \
+       8.png \
+; do
+       run_metaflac --import-picture-from="5|image/png|$f||pictures/$f" $flacfile
+       check_flac
+       metaflac_test "case$ncase" "--import-picture-from" "--list"
+       ncase=`expr $ncase + 1`
+done
+[ $ncase = 60 ] || die "expected case# to be 60"
+
+fn=export-picture-check
+echo -n "Testing --export-picture-to... "
+run_metaflac --export-picture-to=$fn $flacfile
+check_flac
+cmp $fn pictures/0.gif || die "ERROR, exported picture file and original differ"
+echo OK
+rm -f $fn
+echo -n "Testing --block-number --export-picture-to... "
+run_metaflac --block-number=9 --export-picture-to=$fn $flacfile
+check_flac
+cmp $fn pictures/0.png || die "ERROR, exported picture file and original differ"
+echo OK
+rm -f $fn
+
+run_metaflac --remove --block-type=PICTURE $flacfile
+check_flac
+metaflac_test case60 "--remove --block-type=PICTURE" "--list"
+run_metaflac --import-picture-from="1|image/png|standard_icon|32x32x24|pictures/0.png" $flacfile
+check_flac
+metaflac_test case61 "--import-picture-from" "--list"
+run_metaflac --import-picture-from="2|image/png|icon|64x64x24|pictures/1.png" $flacfile
+check_flac
+metaflac_test case62 "--import-picture-from" "--list"
+
+# UNKNOWN blocks
+echo -n "Testing FLAC file with unknown metadata... "
+cp -p metaflac.flac.in $flacfile
+# remove the VORBIS_COMMENT block so vendor string changes don't interfere with the comparison:
+run_metaflac --remove --block-type=VORBIS_COMMENT --dont-use-padding $flacfile
+cmp $flacfile metaflac.flac.ok || die "ERROR, $flacfile and metaflac.flac.ok differ"
+echo OK
+
+rm -f $testdir/out.flac $testdir/out.meta
+
+exit 0
diff --git a/test/test_seeking.sh b/test/test_seeking.sh
new file mode 100755 (executable)
index 0000000..cf4fff3
--- /dev/null
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/flac:$PATH
+PATH=../src/metaflac:$PATH
+PATH=../src/test_seeking:$PATH
+PATH=../src/test_streams:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+       FLAC__TEST_LEVEL=1
+fi
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+metaflac --help 1>/dev/null 2>/dev/null || die "ERROR can't find metaflac executable"
+
+run_flac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_seeking.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 flac $* 4>>test_seeking.valgrind.log
+       else
+               flac $*
+       fi
+}
+
+run_metaflac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 metaflac $*" >>test_seeking.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 metaflac $* 4>>test_seeking.valgrind.log
+       else
+               metaflac $*
+       fi
+}
+
+run_test_seeking ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 test_seeking $*" >>test_seeking.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 test_seeking $* 4>>test_seeking.valgrind.log
+       else
+               test_seeking $*
+       fi
+}
+
+echo "Checking for --ogg support in flac..."
+if flac --ogg --silent --force-raw-format --endian=little --sign=signed --channels=1 --bps=8 --sample-rate=44100 -c $0 1>/dev/null 2>&1 ; then
+       has_ogg=yes;
+       echo "flac --ogg works"
+else
+       has_ogg=no;
+       echo "flac --ogg doesn't work"
+fi
+
+
+echo "Generating streams..."
+if [ ! -f noise.raw ] ; then
+       test_streams || die "ERROR during test_streams"
+fi
+
+echo "generating FLAC files for seeking:"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 -S- --output-name=tiny.flac noise8m32.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 -S- --output-name=small.flac noise.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 -S10x --output-name=tiny-s.flac noise8m32.raw || die "ERROR generating FLAC file"
+run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 -S10x --output-name=small-s.flac noise.raw || die "ERROR generating FLAC file"
+
+tiny_samples=`metaflac --show-total-samples tiny.flac`
+small_samples=`metaflac --show-total-samples small.flac`
+
+tiny_seek_count=100
+if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+       small_seek_count=10000
+else
+       small_seek_count=100000
+fi
+
+for suffix in '' '-s' ; do
+       echo "testing tiny$suffix.flac:"
+       if run_test_seeking tiny$suffix.flac $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+
+       echo "testing small$suffix.flac:"
+       if run_test_seeking small$suffix.flac $small_seek_count $small_samples noise.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+
+       echo "removing sample count from tiny$suffix.flac and small$suffix.flac:"
+       if run_metaflac --no-filename --set-total-samples=0 tiny$suffix.flac small$suffix.flac ; then : ; else
+               die "ERROR: during metaflac"
+       fi
+
+       echo "testing tiny$suffix.flac with total_samples=0:"
+       if run_test_seeking tiny$suffix.flac $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+
+       echo "testing small$suffix.flac with total_samples=0:"
+       if run_test_seeking small$suffix.flac $small_seek_count $small_samples noise.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+done
+
+if [ $has_ogg = "yes" ] ; then
+
+       echo "generating Ogg FLAC files for seeking:"
+       run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=8 --channels=1 --blocksize=576 --output-name=tiny.oga --ogg noise8m32.raw || die "ERROR generating Ogg FLAC file"
+       run_flac --verify --force --silent --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=16 --channels=2 --blocksize=576 --output-name=small.oga --ogg noise.raw || die "ERROR generating Ogg FLAC file"
+       # seek tables are not used in Ogg FLAC
+
+       echo "testing tiny.oga:"
+       if run_test_seeking tiny.oga $tiny_seek_count $tiny_samples noise8m32.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+
+       echo "testing small.oga:"
+       if run_test_seeking small.oga $small_seek_count $small_samples noise.raw ; then : ; else
+               die "ERROR: during test_seeking"
+       fi
+
+fi
+
+rm -f tiny.flac tiny.oga small.flac small.oga tiny-s.flac small-s.flac
diff --git a/test/test_streams.sh b/test/test_streams.sh
new file mode 100755 (executable)
index 0000000..3b1dc05
--- /dev/null
@@ -0,0 +1,268 @@
+#!/bin/sh
+
+#  FLAC - Free Lossless Audio Codec
+#  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+#
+#  This file is part the FLAC project.  FLAC is comprised of several
+#  components distributed under difference licenses.  The codec libraries
+#  are distributed under Xiph.Org's BSD-like license (see the file
+#  COPYING.Xiph in this distribution).  All other programs, libraries, and
+#  plugins are distributed under the GPL (see COPYING.GPL).  The documentation
+#  is distributed under the Gnu FDL (see COPYING.FDL).  Each file in the
+#  FLAC distribution contains at the top the terms under which it may be
+#  distributed.
+#
+#  Since this particular file is relevant to all components of FLAC,
+#  it may be distributed under the Xiph.Org license, which is the least
+#  restrictive of those mentioned above.  See the file COPYING.Xiph in this
+#  distribution.
+
+die ()
+{
+       echo $* 1>&2
+       exit 1
+}
+
+if [ x = x"$1" ] ; then 
+       BUILD=debug
+else
+       BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/flac:$PATH
+PATH=../src/test_streams:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+       FLAC__TEST_LEVEL=1
+fi
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+       if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+               echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_streams.valgrind.log
+               valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --log-fd=4 flac $* 4>>test_streams.valgrind.log
+       else
+               flac $*
+       fi
+}
+
+echo "Generating streams..."
+if [ ! -f wacky1.wav ] ; then
+       test_streams || die "ERROR during test_streams"
+fi
+
+#
+# single-file test routines
+#
+
+test_file ()
+{
+       name=$1
+       channels=$2
+       bps=$3
+       encode_options="$4"
+
+       echo -n "$name (--channels=$channels --bps=$bps $encode_options): encode..."
+       cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding $name.raw"
+       echo "### ENCODE $name #######################################################" >> ./streams.log
+       echo "###    cmd=$cmd" >> ./streams.log
+       $cmd 2>>./streams.log || die "ERROR during encode of $name"
+
+       echo -n "decode..."
+       cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --output-name=$name.cmp $name.flac"
+       echo "### DECODE $name #######################################################" >> ./streams.log
+       echo "###    cmd=$cmd" >> ./streams.log
+       $cmd 2>>./streams.log || die "ERROR during decode of $name"
+
+       ls -1l $name.raw >> ./streams.log
+       ls -1l $name.flac >> ./streams.log
+       ls -1l $name.cmp >> ./streams.log
+
+       echo -n "compare..."
+       cmp $name.raw $name.cmp || die "ERROR during compare of $name"
+
+       echo OK
+}
+
+test_file_piped ()
+{
+       name=$1
+       channels=$2
+       bps=$3
+       encode_options="$4"
+
+       if [ `env | grep -ic '^comspec='` != 0 ] ; then
+               is_win=yes
+       else
+               is_win=no
+       fi
+
+       echo -n "$name: encode via pipes..."
+       if [ $is_win = yes ] ; then
+               cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding --stdout $name.raw"
+               echo "### ENCODE $name #######################################################" >> ./streams.log
+               echo "###    cmd=$cmd" >> ./streams.log
+               $cmd 1>$name.flac 2>>./streams.log || die "ERROR during encode of $name"
+       else
+               cmd="run_flac --verify --silent --force --force-raw-format --endian=little --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding --stdout -"
+               echo "### ENCODE $name #######################################################" >> ./streams.log
+               echo "###    cmd=$cmd" >> ./streams.log
+               cat $name.raw | $cmd 1>$name.flac 2>>./streams.log || die "ERROR during encode of $name"
+       fi
+       echo -n "decode via pipes..."
+       if [ $is_win = yes ] ; then
+               cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --stdout $name.flac"
+               echo "### DECODE $name #######################################################" >> ./streams.log
+               echo "###    cmd=$cmd" >> ./streams.log
+               $cmd 1>$name.cmp 2>>./streams.log || die "ERROR during decode of $name"
+       else
+               cmd="run_flac --silent --force --endian=little --sign=signed --decode --force-raw-format --stdout -"
+               echo "### DECODE $name #######################################################" >> ./streams.log
+               echo "###    cmd=$cmd" >> ./streams.log
+               cat $name.flac | $cmd 1>$name.cmp 2>>./streams.log || die "ERROR during decode of $name"
+       fi
+       ls -1l $name.raw >> ./streams.log
+       ls -1l $name.flac >> ./streams.log
+       ls -1l $name.cmp >> ./streams.log
+
+       echo -n "compare..."
+       cmp $name.raw $name.cmp || die "ERROR during compare of $name"
+
+       echo OK
+}
+
+if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+       max_lpc_order=32
+else
+       max_lpc_order=16
+fi
+
+echo "Testing noise through pipes..."
+test_file_piped noise 1 8 "-0"
+
+echo "Testing small files..."
+test_file test01 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test02 2 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test03 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+test_file test04 2 16 "-0 -l $max_lpc_order --lax -m -e -p"
+
+for bps in 8 16 24 ; do
+       echo "Testing $bps-bit full-scale deflection streams..."
+       for b in 01 02 03 04 05 06 07 ; do
+               test_file fsd$bps-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e -p"
+       done
+done
+
+echo "Testing 16-bit wasted-bits-per-sample streams..."
+for b in 01 ; do
+       test_file wbps16-$b 1 16 "-0 -l $max_lpc_order --lax -m -e -p"
+done
+
+for bps in 8 16 24 ; do
+       echo "Testing $bps-bit sine wave streams..."
+       for b in 00 ; do
+               test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=48000"
+       done
+       for b in 01 ; do
+               test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=96000"
+       done
+       for b in 02 03 04 ; do
+               test_file sine${bps}-$b 1 $bps "-0 -l $max_lpc_order --lax -m -e"
+       done
+       for b in 10 11 ; do
+               test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=48000"
+       done
+       for b in 12 ; do
+               test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e --sample-rate=96000"
+       done
+       for b in 13 14 15 16 17 18 19 ; do
+               test_file sine${bps}-$b 2 $bps "-0 -l $max_lpc_order --lax -m -e"
+       done
+done
+
+echo "Testing blocksize variations..."
+for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+       for blocksize in 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
+               for lpc_order in 0 1 2 3 4 5 7 8 9 15 16 17 31 32 ; do
+                       if [ $lpc_order = 0 ] || [ $lpc_order -le $blocksize ] ; then
+                               test_file noise8m32 1 8 "-8 -p -e -l $lpc_order --lax --blocksize=$blocksize $disable"
+                       fi
+               done
+       done
+done
+
+echo "Testing some frame header variations..."
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax -b $max_lpc_order"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax -b 65535"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=9"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90000"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=9"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90"
+test_file sine16-01 1 16 "-0 -l $max_lpc_order -m -e -p --lax --sample-rate=90000"
+
+echo "Testing option variations..."
+for f in 00 01 02 03 04 ; do
+       for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+               if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                       for opt in 0 1 2 4 5 6 8 ; do
+                               for extras in '' '-p' '-e' ; do
+                                       if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                                               test_file sine16-$f 1 16 "-$opt $extras $disable"
+                                       fi
+                               done
+                       done
+                       if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+                               test_file sine16-$f 1 16 "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+                       fi
+               fi
+       done
+done
+
+for f in 10 11 12 13 14 15 16 17 18 19 ; do
+       for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+               if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                       for opt in 0 1 2 4 5 6 8 ; do
+                               for extras in '' '-p' '-e' ; do
+                                       if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                                               test_file sine16-$f 2 16 "-$opt $extras $disable"
+                                       fi
+                               done
+                       done
+                       if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+                               test_file sine16-$f 2 16 "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+                       fi
+               fi
+       done
+done
+
+echo "Testing noise..."
+for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+       if [ -z "$disable" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+               for channels in 1 2 4 8 ; do
+                       if [ $channels -le 2 ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                               for bps in 8 16 24 ; do
+                                       for opt in 0 1 2 3 4 5 6 7 8 ; do
+                                               for extras in '' '-p' '-e' ; do
+                                                       if [ -z "$extras" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                                                               for blocksize in '' '--lax -b 32' '--lax -b 32768' '--lax -b 65535' ; do
+                                                                       if [ -z "$blocksize" ] || [ "$FLAC__TEST_LEVEL" -gt 0 ] ; then
+                                                                               test_file noise $channels $bps "-$opt $extras $blocksize $disable"
+                                                                       fi
+                                                               done
+                                                       fi
+                                               done
+                                       done
+                                       if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+                                               test_file noise $channels $bps "-b 16384 -m -r 8 -l $max_lpc_order --lax -e -p $disable"
+                                       fi
+                               done
+                       fi
+               done
+       fi
+done